PSARC/2002/762 Layered Trusted Solaris
authorjpk
Fri, 24 Mar 2006 12:29:20 -0800
changeset 1676 37f4a3e2bd99
parent 1675 5791e75682d0
child 1677 072efdedd007
PSARC/2002/762 Layered Trusted Solaris PSARC/2005/060 TSNET: Trusted Networking with Security Labels PSARC/2005/259 Layered Trusted Solaris Label Interfaces PSARC/2005/573 Solaris Trusted Extensions for Printing PSARC/2005/691 Trusted Extensions for Device Allocation PSARC/2005/723 Solaris Trusted Extensions Filesystem Labeling PSARC/2006/009 Labeled Auditing PSARC/2006/155 Trusted Extensions RBAC Changes PSARC/2006/191 is_system_labeled 6293271 Zone processes should use zone_kcred instead of kcred 6394554 integrate Solaris Trusted Extensions
deleted_files/usr/src/cmd/dminfo/Makefile
usr/src/Makefile.lint
usr/src/Targetdirs
usr/src/cmd/Makefile
usr/src/cmd/allocate/Makefile
usr/src/cmd/allocate/allocate.c
usr/src/cmd/allocate/allocate.h
usr/src/cmd/allocate/allocate3.c
usr/src/cmd/allocate/audio_clean.c
usr/src/cmd/allocate/dminfo.c
usr/src/cmd/allocate/mkdevalloc.c
usr/src/cmd/auditconfig/auditconfig.c
usr/src/cmd/auditreduce/Makefile
usr/src/cmd/auditreduce/auditr.h
usr/src/cmd/auditreduce/auditrd.h
usr/src/cmd/auditreduce/auditrt.h
usr/src/cmd/auditreduce/option.c
usr/src/cmd/auditreduce/token.c
usr/src/cmd/bsmconv/bsmconv.sh
usr/src/cmd/bsmunconv/bsmunconv.sh
usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile
usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
usr/src/cmd/cmd-inet/usr.sbin/Makefile
usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c
usr/src/cmd/cmd-inet/usr.sbin/route.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c
usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
usr/src/cmd/devfsadm/Makefile.com
usr/src/cmd/devfsadm/audio_link.c
usr/src/cmd/devfsadm/devalloc.c
usr/src/cmd/devfsadm/devfsadm.c
usr/src/cmd/devfsadm/disk_link.c
usr/src/cmd/devfsadm/i386/misc_link_i386.c
usr/src/cmd/devfsadm/sparc/misc_link_sparc.c
usr/src/cmd/devfsadm/tape_link.c
usr/src/cmd/devfsadm/usb_link.c
usr/src/cmd/dminfo/Makefile
usr/src/cmd/dminfo/dminfo.c
usr/src/cmd/fs.d/autofs/auto_subr.c
usr/src/cmd/fs.d/autofs/autod_lookup.c
usr/src/cmd/fs.d/autofs/autod_main.c
usr/src/cmd/fs.d/autofs/autod_nfs.c
usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c
usr/src/cmd/fs.d/nfs/mountd/mountd.c
usr/src/cmd/fs.d/nfs/nfsd/nfsd.c
usr/src/cmd/fs.d/nfs/statd/sm_svc.c
usr/src/cmd/ldap/Makefile.com
usr/src/cmd/ldap/ns_ldap/idsconfig.sh
usr/src/cmd/ldap/ns_ldap/ldapaddent.c
usr/src/cmd/ldap/ns_ldap/ldapaddent.h
usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c
usr/src/cmd/ldap/ns_ldap/ldapaddtsol.c
usr/src/cmd/ldap/ns_ldap/mapping.c
usr/src/cmd/lp/cmd/Makefile
usr/src/cmd/lp/cmd/adaptor/Makefile
usr/src/cmd/lp/cmd/adaptor/cancel_job.c
usr/src/cmd/lp/cmd/adaptor/misc.c
usr/src/cmd/lp/cmd/adaptor/misc.h
usr/src/cmd/lp/cmd/adaptor/show_queue.c
usr/src/cmd/lp/cmd/adaptor/submit_job.c
usr/src/cmd/lp/cmd/lpadmin/Makefile
usr/src/cmd/lp/cmd/lpadmin/do_printer.c
usr/src/cmd/lp/cmd/lpadmin/lpadmin.c
usr/src/cmd/lp/cmd/lpadmin/lpadmin.h
usr/src/cmd/lp/cmd/lpadmin/rmdest.c
usr/src/cmd/lp/cmd/lpc/process.c
usr/src/cmd/lp/cmd/lpc/topq.c
usr/src/cmd/lp/cmd/lpsched/Makefile
usr/src/cmd/lp/cmd/lpsched/disp1.c
usr/src/cmd/lp/cmd/lpsched/dispatch.h
usr/src/cmd/lp/cmd/lpsched/disptab.c
usr/src/cmd/lp/cmd/lpsched/exec.c
usr/src/cmd/lp/cmd/lpsched/validate.c
usr/src/cmd/lp/cmd/lpstat/Makefile
usr/src/cmd/lp/cmd/lpstat/lpstat.h
usr/src/cmd/lp/cmd/lpstat/output.c
usr/src/cmd/lp/cmd/lpstat/request.c
usr/src/cmd/lp/cmd/lpsystem.c
usr/src/cmd/lp/include/lp.h
usr/src/cmd/lp/include/msgs.h
usr/src/cmd/lp/include/secure.h
usr/src/cmd/lp/lib/access/allowed.c
usr/src/cmd/lp/lib/lp/Makefile
usr/src/cmd/lp/lib/lp/tx.c
usr/src/cmd/lp/lib/msgs/mlisten.c
usr/src/cmd/lp/lib/msgs/msgfmts.c
usr/src/cmd/lp/lib/papi/Makefile
usr/src/cmd/lp/lib/papi/job.c
usr/src/cmd/lp/lib/papi/lpsched-jobs.c
usr/src/cmd/lp/lib/papi/mapfile-vers
usr/src/cmd/lp/lib/papi/papi_impl.h
usr/src/cmd/lp/lib/papi/printer.c
usr/src/cmd/lp/lib/papi/service.c
usr/src/cmd/lp/lib/secure/secure.c
usr/src/cmd/mdb/common/modules/genunix/genunix.c
usr/src/cmd/mdb/common/modules/genunix/net.c
usr/src/cmd/mdb/common/modules/genunix/tsol.c
usr/src/cmd/mdb/common/modules/genunix/tsol.h
usr/src/cmd/mdb/intel/amd64/genunix/Makefile
usr/src/cmd/mdb/intel/ia32/genunix/Makefile
usr/src/cmd/mdb/sparc/v9/genunix/Makefile
usr/src/cmd/netfiles/nsswitch.dns
usr/src/cmd/netfiles/nsswitch.files
usr/src/cmd/netfiles/nsswitch.ldap
usr/src/cmd/nscd/server.c
usr/src/cmd/nscd/svc-nscd
usr/src/cmd/praudit/Makefile
usr/src/cmd/praudit/token.c
usr/src/cmd/praudit/toktable.c
usr/src/cmd/praudit/toktable.h
usr/src/cmd/print/gateway/adaptor.c
usr/src/cmd/print/gateway/adaptor.h
usr/src/cmd/print/gateway/main.c
usr/src/cmd/ptools/ppriv/ppriv.c
usr/src/cmd/rpcbind/bind.xml
usr/src/cmd/rpcbind/rpcbind.c
usr/src/cmd/smserverd/myaudit.c
usr/src/cmd/svc/shell/smf_include.sh
usr/src/cmd/tar/Makefile
usr/src/cmd/tar/tar.c
usr/src/cmd/truss/Makefile.com
usr/src/cmd/truss/expound.c
usr/src/cmd/truss/print.c
usr/src/cmd/truss/print.h
usr/src/cmd/truss/systable.c
usr/src/cmd/volmgt/rmm/Makefile
usr/src/cmd/volmgt/rmm/rmm.c
usr/src/cmd/zoneadm/zoneadm.c
usr/src/cmd/zoneadmd/Makefile
usr/src/cmd/zoneadmd/vplat.c
usr/src/common/ipf/ip_compat.h
usr/src/common/tsol/blabel.c
usr/src/head/auth_list.h
usr/src/head/nss_dbdefs.h
usr/src/head/protocols/routed.h
usr/src/head/tar.h
usr/src/head/ucred.h
usr/src/head/user_attr.h
usr/src/head/zone.h
usr/src/lib/Makefile
usr/src/lib/auditd_plugins/syslog/systoken.c
usr/src/lib/auditd_plugins/syslog/systoken.h
usr/src/lib/common/inc/c_synonyms.h
usr/src/lib/libbsm/Makefile
usr/src/lib/libbsm/Makefile.com
usr/src/lib/libbsm/audit_class.txt
usr/src/lib/libbsm/audit_event.txt
usr/src/lib/libbsm/common/adt_token.c
usr/src/lib/libbsm/common/au_to.c
usr/src/lib/libbsm/common/audit_allocate.c
usr/src/lib/libbsm/common/audit_ftpd.c
usr/src/lib/libbsm/common/audit_rexd.c
usr/src/lib/libbsm/common/audit_rexecd.c
usr/src/lib/libbsm/common/audit_rshd.c
usr/src/lib/libbsm/common/devalloc.c
usr/src/lib/libbsm/common/devalloc.h
usr/src/lib/libbsm/common/devices.h
usr/src/lib/libbsm/common/generic.c
usr/src/lib/libbsm/common/getdadefs.c
usr/src/lib/libbsm/common/getdaent.c
usr/src/lib/libbsm/common/getdevicerange.c
usr/src/lib/libbsm/common/getdment.c
usr/src/lib/libbsm/common/llib-lbsm
usr/src/lib/libbsm/mkhdr.sh
usr/src/lib/libbsm/spec/Makefile.targ
usr/src/lib/libbsm/spec/devalloc.spec
usr/src/lib/libbsm/spec/private.spec
usr/src/lib/libc/amd64/Makefile
usr/src/lib/libc/i386/Makefile.com
usr/src/lib/libc/inc/synonyms.h
usr/src/lib/libc/port/gen/ucred.c
usr/src/lib/libc/port/llib-lc
usr/src/lib/libc/port/sys/label.c
usr/src/lib/libc/port/sys/zone.c
usr/src/lib/libc/sparc/Makefile
usr/src/lib/libc/sparcv9/Makefile
usr/src/lib/libc/spec/gen.spec
usr/src/lib/libc/spec/sys.spec
usr/src/lib/libc/spec/versions
usr/src/lib/libipsecutil/common/ipsec_util.h
usr/src/lib/libldap5/Makefile.com
usr/src/lib/libnsl/Makefile
usr/src/lib/libnsl/Makefile.com
usr/src/lib/libnsl/nss/nss.h
usr/src/lib/libnsl/rpc/clnt_bcast.c
usr/src/lib/libnsl/rpc/clnt_generic.c
usr/src/lib/libnsl/rpc/rpc_mt.h
usr/src/lib/libnsl/rpc/svc_dg.c
usr/src/lib/libnsl/rpc/svc_generic.c
usr/src/lib/libnsl/rpc/ti_opts.c
usr/src/lib/libsldap/common/ns_common.c
usr/src/lib/libsldap/common/ns_sldap.h
usr/src/lib/libsldap/common/ns_writes.c
usr/src/lib/libtsnet/Makefile
usr/src/lib/libtsnet/Makefile.com
usr/src/lib/libtsnet/amd64/Makefile
usr/src/lib/libtsnet/common/libtsnet.h
usr/src/lib/libtsnet/common/llib-ltsnet
usr/src/lib/libtsnet/common/misc.c
usr/src/lib/libtsnet/common/synonyms.h
usr/src/lib/libtsnet/common/tnmlp.c
usr/src/lib/libtsnet/common/tnrh.c
usr/src/lib/libtsnet/common/tnrhtp.c
usr/src/lib/libtsnet/common/tsol_getrhent.c
usr/src/lib/libtsnet/common/tsol_gettpent.c
usr/src/lib/libtsnet/common/tsol_getzcent.c
usr/src/lib/libtsnet/common/tsol_sgetrhent.c
usr/src/lib/libtsnet/common/tsol_sgettpent.c
usr/src/lib/libtsnet/common/tsol_sgetzcent.c
usr/src/lib/libtsnet/i386/Makefile
usr/src/lib/libtsnet/sparc/Makefile
usr/src/lib/libtsnet/sparcv9/Makefile
usr/src/lib/libtsnet/spec/Makefile
usr/src/lib/libtsnet/spec/Makefile.targ
usr/src/lib/libtsnet/spec/amd64/Makefile
usr/src/lib/libtsnet/spec/i386/Makefile
usr/src/lib/libtsnet/spec/sparc/Makefile
usr/src/lib/libtsnet/spec/sparcv9/Makefile
usr/src/lib/libtsnet/spec/tsnet.spec
usr/src/lib/libtsnet/spec/versions
usr/src/lib/libtsol/Makefile
usr/src/lib/libtsol/Makefile.com
usr/src/lib/libtsol/amd64/Makefile
usr/src/lib/libtsol/common/btohex.c
usr/src/lib/libtsol/common/btos.c
usr/src/lib/libtsol/common/call_labeld.c
usr/src/lib/libtsol/common/clnt.h
usr/src/lib/libtsol/common/getlabel.c
usr/src/lib/libtsol/common/getpathbylabel.c
usr/src/lib/libtsol/common/getplabel.c
usr/src/lib/libtsol/common/hextob.c
usr/src/lib/libtsol/common/label.h
usr/src/lib/libtsol/common/labeld.h
usr/src/lib/libtsol/common/llib-ltsol
usr/src/lib/libtsol/common/ltos.c
usr/src/lib/libtsol/common/misc.c
usr/src/lib/libtsol/common/private.c
usr/src/lib/libtsol/common/privlib.c
usr/src/lib/libtsol/common/setflabel.c
usr/src/lib/libtsol/common/stob.c
usr/src/lib/libtsol/common/stol.c
usr/src/lib/libtsol/common/zone.c
usr/src/lib/libtsol/i386/Makefile
usr/src/lib/libtsol/sparc/Makefile
usr/src/lib/libtsol/sparcv9/Makefile
usr/src/lib/libtsol/spec/Makefile
usr/src/lib/libtsol/spec/Makefile.targ
usr/src/lib/libtsol/spec/amd64/Makefile
usr/src/lib/libtsol/spec/i386/Makefile
usr/src/lib/libtsol/spec/obsolete.spec
usr/src/lib/libtsol/spec/private.spec
usr/src/lib/libtsol/spec/sparc/Makefile
usr/src/lib/libtsol/spec/sparcv9/Makefile
usr/src/lib/libtsol/spec/tsol.spec
usr/src/lib/libtsol/spec/versions
usr/src/lib/libzonecfg/common/libzonecfg.c
usr/src/lib/nsswitch/files/Makefile.com
usr/src/lib/nsswitch/files/common/mapfile-vers
usr/src/lib/nsswitch/files/common/tsol_getrhent.c
usr/src/lib/nsswitch/files/common/tsol_gettpent.c
usr/src/lib/nsswitch/ldap/Makefile.com
usr/src/lib/nsswitch/ldap/common/ldap_common.c
usr/src/lib/nsswitch/ldap/common/ldap_common.h
usr/src/lib/nsswitch/ldap/common/mapfile-vers
usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c
usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c
usr/src/pkgdefs/SUNWarc/prototype_com
usr/src/pkgdefs/SUNWarc/prototype_i386
usr/src/pkgdefs/SUNWarc/prototype_sparc
usr/src/pkgdefs/SUNWarcr/prototype_com
usr/src/pkgdefs/SUNWarcr/prototype_i386
usr/src/pkgdefs/SUNWarcr/prototype_sparc
usr/src/pkgdefs/SUNWcsl/prototype_com
usr/src/pkgdefs/SUNWcsl/prototype_i386
usr/src/pkgdefs/SUNWcsl/prototype_sparc
usr/src/pkgdefs/SUNWcslr/prototype_com
usr/src/pkgdefs/SUNWcslr/prototype_i386
usr/src/pkgdefs/SUNWcslr/prototype_sparc
usr/src/pkgdefs/SUNWcsr/prototype_com
usr/src/pkgdefs/SUNWcsu/prototype_com
usr/src/pkgdefs/SUNWhea/prototype_com
usr/src/pkgdefs/common_files/i.nsswitch
usr/src/pkgdefs/etc/exception_list_i386
usr/src/pkgdefs/etc/exception_list_sparc
usr/src/tools/abi/etc/exceptions
usr/src/uts/common/Makefile.files
usr/src/uts/common/Makefile.rules
usr/src/uts/common/c2/audit.c
usr/src/uts/common/c2/audit.h
usr/src/uts/common/c2/audit_event.c
usr/src/uts/common/c2/audit_kevents.h
usr/src/uts/common/c2/audit_record.h
usr/src/uts/common/c2/audit_start.c
usr/src/uts/common/c2/audit_token.c
usr/src/uts/common/disp/thread.c
usr/src/uts/common/fs/autofs/auto_vfsops.c
usr/src/uts/common/fs/doorfs/door_vnops.c
usr/src/uts/common/fs/lofs/lofs_vfsops.c
usr/src/uts/common/fs/nfs/nfs3_vfsops.c
usr/src/uts/common/fs/nfs/nfs4_srv.c
usr/src/uts/common/fs/nfs/nfs4_subr.c
usr/src/uts/common/fs/nfs/nfs4_vfsops.c
usr/src/uts/common/fs/nfs/nfs_subr.c
usr/src/uts/common/fs/nfs/nfs_vfsops.c
usr/src/uts/common/fs/sockfs/socksyscalls.c
usr/src/uts/common/inet/ip.h
usr/src/uts/common/inet/ip/icmp.c
usr/src/uts/common/inet/ip/icmp_opt_data.c
usr/src/uts/common/inet/ip/igmp.c
usr/src/uts/common/inet/ip/ip.c
usr/src/uts/common/inet/ip/ip6.c
usr/src/uts/common/inet/ip/ip6_if.c
usr/src/uts/common/inet/ip/ip6_ire.c
usr/src/uts/common/inet/ip/ip6_rts.c
usr/src/uts/common/inet/ip/ip_if.c
usr/src/uts/common/inet/ip/ip_ire.c
usr/src/uts/common/inet/ip/ip_mroute.c
usr/src/uts/common/inet/ip/ip_multi.c
usr/src/uts/common/inet/ip/ip_ndp.c
usr/src/uts/common/inet/ip/ip_opt_data.c
usr/src/uts/common/inet/ip/ip_rts.c
usr/src/uts/common/inet/ip/ipclassifier.c
usr/src/uts/common/inet/ip/ipsecah.c
usr/src/uts/common/inet/ip/nattymod.c
usr/src/uts/common/inet/ip/spd.c
usr/src/uts/common/inet/ip/tn_ipopt.c
usr/src/uts/common/inet/ip/tnet.c
usr/src/uts/common/inet/ip6.h
usr/src/uts/common/inet/ip_if.h
usr/src/uts/common/inet/ip_ire.h
usr/src/uts/common/inet/ip_ndp.h
usr/src/uts/common/inet/ip_rts.h
usr/src/uts/common/inet/ipclassifier.h
usr/src/uts/common/inet/mib2.h
usr/src/uts/common/inet/nd.h
usr/src/uts/common/inet/optcom.c
usr/src/uts/common/inet/optcom.h
usr/src/uts/common/inet/rawip_impl.h
usr/src/uts/common/inet/sctp/sctp.c
usr/src/uts/common/inet/sctp/sctp_addr.c
usr/src/uts/common/inet/sctp/sctp_asconf.c
usr/src/uts/common/inet/sctp/sctp_asconf.h
usr/src/uts/common/inet/sctp/sctp_bind.c
usr/src/uts/common/inet/sctp/sctp_common.c
usr/src/uts/common/inet/sctp/sctp_conn.c
usr/src/uts/common/inet/sctp/sctp_cookie.c
usr/src/uts/common/inet/sctp/sctp_error.c
usr/src/uts/common/inet/sctp/sctp_hash.c
usr/src/uts/common/inet/sctp/sctp_heartbeat.c
usr/src/uts/common/inet/sctp/sctp_impl.h
usr/src/uts/common/inet/sctp/sctp_input.c
usr/src/uts/common/inet/sctp/sctp_opt_data.c
usr/src/uts/common/inet/sctp/sctp_output.c
usr/src/uts/common/inet/sctp/sctp_snmp.c
usr/src/uts/common/inet/sctp/sctp_timer.c
usr/src/uts/common/inet/sctp_ip.h
usr/src/uts/common/inet/tcp.h
usr/src/uts/common/inet/tcp/tcp.c
usr/src/uts/common/inet/tcp/tcp_opt_data.c
usr/src/uts/common/inet/udp/udp.c
usr/src/uts/common/inet/udp/udp_opt_data.c
usr/src/uts/common/inet/udp_impl.h
usr/src/uts/common/io/tl.c
usr/src/uts/common/net/route.h
usr/src/uts/common/netinet/ip6.h
usr/src/uts/common/nfs/nfs.h
usr/src/uts/common/os/cred.c
usr/src/uts/common/os/exec.c
usr/src/uts/common/os/labelsys.c
usr/src/uts/common/os/main.c
usr/src/uts/common/os/policy.c
usr/src/uts/common/os/priv_defs
usr/src/uts/common/os/sysent.c
usr/src/uts/common/os/tlabel.c
usr/src/uts/common/os/zone.c
usr/src/uts/common/rpc/clnt_clts.c
usr/src/uts/common/rpc/clnt_cots.c
usr/src/uts/common/rpc/svc.c
usr/src/uts/common/rpc/svc.h
usr/src/uts/common/sys/Makefile
usr/src/uts/common/sys/Makefile.syshdrs
usr/src/uts/common/sys/cred.h
usr/src/uts/common/sys/cred_impl.h
usr/src/uts/common/sys/policy.h
usr/src/uts/common/sys/priv.h
usr/src/uts/common/sys/socket.h
usr/src/uts/common/sys/strsun.h
usr/src/uts/common/sys/syscall.h
usr/src/uts/common/sys/tsol/label.h
usr/src/uts/common/sys/tsol/label_macro.h
usr/src/uts/common/sys/tsol/priv.h
usr/src/uts/common/sys/tsol/tndb.h
usr/src/uts/common/sys/tsol/tnet.h
usr/src/uts/common/sys/tsol/tsyscall.h
usr/src/uts/common/sys/ucred.h
usr/src/uts/common/sys/zone.h
usr/src/uts/common/syscall/ppriv.c
usr/src/uts/common/syscall/sendfile.c
usr/src/uts/common/syscall/ucredsys.c
usr/src/uts/i86pc/os/startup.c
usr/src/uts/req.flg
usr/src/uts/sun4/os/startup.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/dminfo/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1989, 2002 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+PROG= dminfo
+
+OBJS=	dminfo.o
+SRCS=	$(OBJS:%.o=%.c)
+
+include ../Makefile.cmd
+
+TEXT_DOMAIN=SUNW_BSM_DMINFO
+POS=dminfo.po
+include ../Makefile.cmd.bsm
+
+FILEMODE=	755
+
+LDLIBS += -lbsm
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTUSRSBINPROG)
+
+clean:
+	rm -rf $(OBJS) $(POS)
+
+lint:	lint_PROG
+
+include ../Makefile.targ
--- a/usr/src/Makefile.lint	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/Makefile.lint	Fri Mar 24 12:29:20 2006 -0800
@@ -350,6 +350,8 @@
 	lib/libsmbios \
 	lib/libsmedia \
 	lib/libthread \
+	lib/libtsnet \
+	lib/libtsol \
 	lib/libumem \
 	lib/libuutil \
 	lib/libwanboot \
--- a/usr/src/Targetdirs	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/Targetdirs	Fri Mar 24 12:29:20 2006 -0800
@@ -200,6 +200,7 @@
 	/usr/include/kerberosv5 \
 	/usr/include/libmilter \
 	/usr/include/sasl \
+	/usr/include/tsol \
 	/usr/lib \
 	/usr/lib/abi \
 	/usr/lib/class \
@@ -860,6 +861,10 @@
 $(ROOT)/usr/lib/libthread.so:=		REALPATH=../../lib/libthread.so.1
 $(ROOT)/usr/lib/libthread_db.so.1:=	REALPATH=../../lib/libc_db.so.1
 $(ROOT)/usr/lib/libthread_db.so:=	REALPATH=../../lib/libc_db.so.1
+$(ROOT)/usr/lib/libtsnet.so.1:=		REALPATH=../../lib/libtsnet.so.1
+$(ROOT)/usr/lib/libtsnet.so:=		REALPATH=../../lib/libtsnet.so.1
+$(ROOT)/usr/lib/libtsol.so.2:=		REALPATH=../../lib/libtsol.so.2
+$(ROOT)/usr/lib/libtsol.so:=		REALPATH=../../lib/libtsol.so.2
 $(ROOT)/usr/lib/libumem.so.1:=		REALPATH=../../lib/libumem.so.1
 $(ROOT)/usr/lib/libumem.so:=		REALPATH=../../lib/libumem.so.1
 $(ROOT)/usr/lib/libuuid.so.1:=		REALPATH=../../lib/libuuid.so.1
@@ -960,6 +965,10 @@
 $(ROOT)/usr/lib/llib-lthread:=		REALPATH=../../lib/llib-lthread
 $(ROOT)/usr/lib/llib-lthread_db.ln:=	REALPATH=../../lib/llib-lc_db.ln
 $(ROOT)/usr/lib/llib-lthread_db:=	REALPATH=../../lib/llib-lc_db
+$(ROOT)/usr/lib/llib-ltsnet.ln:=	REALPATH=../../lib/llib-ltsnet.ln
+$(ROOT)/usr/lib/llib-ltsnet:=		REALPATH=../../lib/llib-ltsnet
+$(ROOT)/usr/lib/llib-ltsol.ln:=		REALPATH=../../lib/llib-ltsol.ln
+$(ROOT)/usr/lib/llib-ltsol:=		REALPATH=../../lib/llib-ltsol
 $(ROOT)/usr/lib/llib-lumem.ln:=		REALPATH=../../lib/llib-lumem.ln
 $(ROOT)/usr/lib/llib-lumem:=		REALPATH=../../lib/llib-lumem
 $(ROOT)/usr/lib/llib-luuid.ln:=		REALPATH=../../lib/llib-luuid.ln
@@ -1165,6 +1174,14 @@
 	REALPATH=../../../lib/$(MACH64)/libc_db.so.1
 $(ROOT)/usr/lib/$(MACH64)/libthread_db.so:= \
 	REALPATH=../../../lib/$(MACH64)/libc_db.so.1
+$(ROOT)/usr/lib/$(MACH64)/libtsnet.so.1:= \
+	REALPATH=../../../lib/$(MACH64)/libtsnet.so.1
+$(ROOT)/usr/lib/$(MACH64)/libtsnet.so:= \
+	REALPATH=../../../lib/$(MACH64)/libtsnet.so.1
+$(ROOT)/usr/lib/$(MACH64)/libtsol.so.2:= \
+	REALPATH=../../../lib/$(MACH64)/libtsol.so.2
+$(ROOT)/usr/lib/$(MACH64)/libtsol.so:= \
+	REALPATH=../../../lib/$(MACH64)/libtsol.so.2
 $(ROOT)/usr/lib/$(MACH64)/libumem.so.1:= \
 	REALPATH=../../../lib/$(MACH64)/libumem.so.1
 $(ROOT)/usr/lib/$(MACH64)/libumem.so:= \
@@ -1275,6 +1292,10 @@
 	REALPATH=../../../lib/$(MACH64)/llib-lthread.ln
 $(ROOT)/usr/lib/$(MACH64)/llib-lthread_db.ln:= \
 	REALPATH=../../../lib/$(MACH64)/llib-lc_db.ln
+$(ROOT)/usr/lib/$(MACH64)/llib-ltsnet.ln:= \
+	REALPATH=../../../lib/$(MACH64)/llib-ltsnet.ln
+$(ROOT)/usr/lib/$(MACH64)/llib-ltsol.ln:= \
+	REALPATH=../../../lib/$(MACH64)/llib-ltsol.ln
 $(ROOT)/usr/lib/$(MACH64)/llib-lumem.ln:= \
 	REALPATH=../../../lib/$(MACH64)/llib-lumem.ln
 $(ROOT)/usr/lib/$(MACH64)/llib-luuid.ln:= \
@@ -1402,6 +1423,8 @@
 	/usr/lib/libsendfile.so.1 \
 	/usr/lib/libsocket.so \
 	/usr/lib/libsocket.so.1 \
+	/usr/lib/libsysevent.so \
+	/usr/lib/libsysevent.so.1 \
 	/usr/lib/libtermcap.so \
 	/usr/lib/libtermcap.so.1 \
 	/usr/lib/libtermlib.so \
@@ -1410,8 +1433,10 @@
 	/usr/lib/libthread.so.1 \
 	/usr/lib/libthread_db.so \
 	/usr/lib/libthread_db.so.1 \
-	/usr/lib/libsysevent.so \
-	/usr/lib/libsysevent.so.1 \
+	/usr/lib/libtsnet.so \
+	/usr/lib/libtsnet.so.1 \
+	/usr/lib/libtsol.so \
+	/usr/lib/libtsol.so.2 \
 	/usr/lib/libumem.so \
 	/usr/lib/libumem.so.1 \
 	/usr/lib/libuuid.so \
@@ -1512,6 +1537,10 @@
 	/usr/lib/llib-lthread.ln \
 	/usr/lib/llib-lthread_db \
 	/usr/lib/llib-lthread_db.ln \
+	/usr/lib/llib-ltsnet \
+	/usr/lib/llib-ltsnet.ln \
+	/usr/lib/llib-ltsol \
+	/usr/lib/llib-ltsol.ln \
 	/usr/lib/llib-lumem \
 	/usr/lib/llib-lumem.ln \
 	/usr/lib/llib-luuid \
@@ -1633,6 +1662,10 @@
 	/usr/lib/$(MACH64)/libthread.so.1 \
 	/usr/lib/$(MACH64)/libthread_db.so \
 	/usr/lib/$(MACH64)/libthread_db.so.1 \
+	/usr/lib/$(MACH64)/libtsnet.so \
+	/usr/lib/$(MACH64)/libtsnet.so.1 \
+	/usr/lib/$(MACH64)/libtsol.so \
+	/usr/lib/$(MACH64)/libtsol.so.2 \
 	/usr/lib/$(MACH64)/libumem.so \
 	/usr/lib/$(MACH64)/libumem.so.1 \
 	/usr/lib/$(MACH64)/libuuid.so \
@@ -1688,6 +1721,8 @@
 	/usr/lib/$(MACH64)/llib-ltermlib.ln \
 	/usr/lib/$(MACH64)/llib-lthread.ln \
 	/usr/lib/$(MACH64)/llib-lthread_db.ln \
+	/usr/lib/$(MACH64)/llib-ltsnet.ln \
+	/usr/lib/$(MACH64)/llib-ltsol.ln \
 	/usr/lib/$(MACH64)/llib-lumem.ln \
 	/usr/lib/$(MACH64)/llib-luuid.ln \
 	/usr/lib/$(MACH64)/llib-lxnet.ln \
--- a/usr/src/cmd/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -720,7 +722,6 @@
 	auditd		\
 	auditreduce	\
 	auditstat	\
-	dminfo		\
 	praudit		\
 	bsmconv		\
 	bsmrecord	\
--- a/usr/src/cmd/allocate/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -33,87 +33,123 @@
 ROOTSECLIB =	$(ROOTSEC)/lib
 ROOTDIRS =	$(ROOTSECDEV) $(ROOTSECLIB)
 
-PROG1 =		allocate
-PROG2 =		mkdevmaps mkdevalloc
-PROG3 =		audio_clean
-PROG =		$(PROG1) $(PROG2) $(PROG3)
-DEFILE =	deallocate
-LISTFILE =	list_devices
 RTLCKS =	audio fd0 sr0 st0 st1
-SCRIPTS =	st_clean fd_clean sr_clean
+SCRIPTS =	fd_clean  sr_clean  st_clean
 ALLSCRIPTS =	allscripts.sh
 
-POFILE=		allocate_all.po
-POFILES=	$(OBJS:%.o=%.po) $(ALLSCRIPTS:%.sh=%.po)
+PROGalloc =	allocate
+PROGmkdevalloc =	mkdevalloc
+PROGdminfo =	dminfo
+PROGaudio =	audio_clean
+PROG =		$(PROGalloc) $(PROGmkdevalloc) $(PROGdminfo) $(PROGaudio)
 
-# make DFLAGS=-DDEBUG
+LINKPROGalloc =	deallocate list_devices
+LINKPROGmkdevalloc = mkdevmaps
+
 
-DFLAGS=
+POFILE =	allocate_all.po
+POFILES =	$(OBJS:%.o=%.po) $(ALLSCRIPTS:%.sh=%.po)
+
+DFLAGS +=	-D_REENTRANT
 CPPFLAGS +=	$(DFLAGS)
 
-ROOTPROG =	$(PROG1:%=$(ROOTUSRSBIN)/%) $(PROG2:%=$(ROOTUSRSBIN)/%) \
-		$(PROG3:%=$(ROOTSECLIB)/%)
-ROOTLOCKS=	$(RTLCKS:%=$(ROOTSECDEV)/%)
-ROOTSCRIPTS=	$(SCRIPTS:%=$(ROOTSECLIB)/%)
+ROOTLOCKS =	$(RTLCKS:%=$(ROOTSECDEV)/%)
+ROOTSCRIPTS =	$(SCRIPTS:%=$(ROOTSECLIB)/%)
 
-CLOBBERFILES += $(SCRIPTS)
+ROOTPROG =	$(PROGallocate:%=$(ROOTUSRSBIN)/%) \
+		$(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%) \
+		$(PROGdminfo:%=$(ROOTUSRSBIN)/%) \
+		$(PROGaudio:%=$(ROOTSECLIB)/%)
+ROOTLINKalloc =	$(LINKPROGalloc:%=$(ROOTUSRSBIN)/%)
+ROOTLINKmkdevalloc = $(LINKPROGmkdevalloc:%=$(ROOTUSRSBIN)/%)
+ROOTLINKS =	$(ROOTLINKalloc) $(ROOTLINKmkdevalloc)
 
-allocate :=	POBJS = allocate.o  allocate3.o
-mkdevmaps :=	POBJS = mkdevmaps.o
-mkdevalloc :=	POBJS = mkdevalloc.o
-audio_clean :=	POBJS = audio_clean.o
+PROGallocOBJS =		allocate.o allocate3.o
+PROGmkdevallocOBJS =	mkdevalloc.o
+PROGdminfoOBJS =	dminfo.o
+PROGaudioOBJS =		audio_clean.o
 
-OBJS =		allocate.o allocate3.o audio_clean.o mkdevmaps.o mkdevalloc.o
+OBJS =		$(PROGallocOBJS) \
+		$(PROGmkdevallocOBJS) \
+		$(PROGdminfoOBJS) \
+		$(PROGaudioOBJS)
+
 SRCS =		$(OBJS:%.o=%.c)
 
-FILEMODE=       0755
-DIRMODE=        0755
-OWNER=          root
-GROUP=          sys
-
+$(ROOTUSRSBIN)/% :=	FILEMODE = 555
+$(ROOTUSRSBIN)/allocate :=	FILEMODE = 4555
 $(ROOTUSRSBIN)/% :=     OWNER = root 
 $(ROOTUSRSBIN)/% :=     GROUP = bin 
-
-$(ROOTUSRSBIN)/allocate := 	FILEMODE = 04755
-$(ROOTUSRSBIN)/deallocate :=	FILEMODE = 04755
-$(ROOTUSRSBIN)/list_devices :=	FILEMODE = 04755
+$(ROOTSECDEV)/% :=	FILEMODE = 0400
+$(ROOTSECDEV)/% :=	OWNER = root
+$(ROOTSECDEV)/% :=	GROUP = bin
+$(ROOTSECLIB)/% :=	FILEMODE = 0555
+$(ROOTSECLIB)/% :=	OWNER = root
+$(ROOTSECLIB)/% :=	GROUP = sys
 
-$(ROOTSECDEV)/% :=		FILEMODE = 0400
-$(ROOTSECDEV)/% :=              OWNER = root
-$(ROOTSECDEV)/% :=              GROUP = bin
+LAZYLIBS =	$(ZLAZYLOAD) -ltsol -lgen $(ZNOLAZYLOAD)
+lint :=		LDLIBS += -lbsm -lsec -lsecdb -ltsol -lgen
+$(PROGalloc) :=		LDLIBS += -lbsm -lsec -lsecdb $(LAZYLIBS)
+$(PROGmkdevalloc) :=	LDLIBS += -lbsm
+$(PROGdminfo) :=	LDLIBS += -lbsm
+$(PROGaudio) :=		LDLIBS += -lbsm
 
-$(ROOTSECLIB)/% :=		FILEMODE = 0751
-
-allocate :=	LDLIBS += -lbsm -lsec -lsecdb
+CLOBBERFILES +=	$(SCRIPTS)
 
 .KEEP_STATE:
 
 all :		$(PROG) $(RTLCKS) $(SCRIPTS)
 
-install :	all $(ROOTDIRS) $(ROOTPROG) $(ROOTLOCKS) $(ROOTSCRIPTS)
-		$(RM) $(ROOTUSRSBIN)/$(DEFILE)
-		$(LN) $(ROOTUSRSBIN)/$(PROG1) $(ROOTUSRSBIN)/$(DEFILE)
-		$(RM) $(ROOTUSRSBIN)/$(LISTFILE)
-		$(LN) $(ROOTUSRSBIN)/$(PROG1) $(ROOTUSRSBIN)/$(LISTFILE)
-
-$(PROG) :	$$(POBJS)
-		$(LINK.c) $(POBJS) -o $@ $(LDLIBS)
-		$(POST_PROCESS)
+install :	$(PROG) $(ROOTDIRS) $(ROOTPROG) $(ROOTLOCKS) \
+		$(ROOTSCRIPTS) $(ROOTLINKS)
 
 $(RTLCKS):
 		$(TOUCH) $@
 
-$(ROOTDIRS):
+$(ROOTSECLIB)/%: %.sh
+		$(INS.rename)
+
+$(PROGalloc) :	$(PROGallocOBJS)
+		$(LINK.c) $(PROGallocOBJS) -o $@ $(LDLIBS)
+		$(POST_PROCESS)
+
+$(PROGmkdevalloc) :	$(PROGmkdevallocOBJS)
+			$(LINK.c) $(PROGmkdevallocOBJS) -o $@ $(LDLIBS)
+			$(POST_PROCESS)
+
+$(PROGdminfo) :	$(PROGdminfoOBJS)
+		$(LINK.c) $(PROGdminfoOBJS) -o $@ $(LDLIBS)
+		$(POST_PROCESS)
+
+$(PROGaudio) :	$(PROGaudioOBJS)
+		$(LINK.c) $(PROGaudioOBJS) -o $@ $(LDLIBS)
+		$(POST_PROCESS)
+
+$(ROOTDIRS) :
 		$(INS.dir)
 
 $(ROOTSECDEV)/%: %
 		$(INS.file)
 
 $(ROOTSECLIB)/%: %
+		$(RM) $@
 		$(INS.file)
 
+$(ROOTSECLIB)/audio_clean :	audio_clean
+				$(RM) $@
+				$(INS.file) $(@F)
+
+$(ROOTLINKalloc) :	$(PROGalloc:%=$(ROOTUSRSBIN)/%)
+			$(RM) $@
+			$(LN) $(PROGalloc:%=$(ROOTUSRSBIN)/%) $@
+
+$(ROOTLINKmkdevalloc) :	$(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%)
+			$(RM) $@
+			$(LN) $(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%) $@
+
 $(POFILE):      $(POFILES)
-		$(RM) $@; $(CAT) $(POFILES) > $@; $(RM)  $(POFILES)
+		$(RM) $@
+		$(CAT) $(POFILES) > $@
 
 #
 # Concatenate all the scripts into one before we build the catalogue.
@@ -124,7 +160,8 @@
 		$(CAT) $(SCRIPTS:%=%.sh) > $@
 
 clean :
-		$(RM) $(OBJS) $(RTLCKS) $(ALLSCRIPTS)
+		$(RM) $(PROG) $(RTLCKS) $(OBJS) \
+		$(SCRIPTS) $(ALLSCRIPTS) $(POFILE) $(POFILES)
 
 lint :		lint_SRCS
 
--- a/usr/src/cmd/allocate/allocate.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/allocate.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -33,140 +33,207 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-
+#include <ctype.h>
+#include <nss_dbdefs.h>
 #include <sys/types.h>
-
+#include <sys/wait.h>
+#include <tsol/label.h>
+#include <zone.h>
+#include <bsm/devalloc.h>
 #include "allocate.h"
 
 #if !defined(TEXT_DOMAIN)
 #define	TEXT_DOMAIN "SUNW_OST_OSCMD"
 #endif
 
+#define	ALLOC	"allocate"
+#define	DEALLOC	"deallocate"
+#define	LIST	"list_devices"
+
 extern void audit_allocate_argv(int, int, char *[]);
 extern int audit_allocate_record(int);
 
+int system_labeled = 0;
+static int windowing = 0;
+static int wdwmsg(char *name, char *msg);
+
 static void
 usage(int func)
 {
-	char *use[7];
+	if (system_labeled) {
+		char *use[9];
 
-	use[0] = gettext("allocate [-s] [-U uname] [-F] device");
-	use[1] = gettext("allocate [-s] [-U uname] -g dev_type");
-	use[2] = gettext("deallocate [-s] [-F] device");
-	use[3] = gettext("deallocate [-s] -I");
-	use[4] = gettext("list_devices [-s] [-U uid] -l [device]");
-	use[5] = gettext("list_devices [-s] [-U uid] -n [device]");
-	use[6] = gettext("list_devices [-s] [-U uid] -u [device]");
+		use[0] = gettext("allocate [-s] [-w] [-U uname] [-z zonename] "
+		    "[-F] device");
+		use[1] = gettext("allocate [-s] [-w] [-U uname] [-z zonename] "
+		    "[-F] -g dev_type");
+		use[2] = gettext("deallocate [-s] [-w] [-z zonename] "
+		    "[-F] device");
+		use[3] = gettext("deallocate [-s] [-w] [-z zonename] "
+		    "[-F] -g dev_type");
+		use[4] = gettext("deallocate [-s] [-w] [-z zonename] -I");
+		use[5] = gettext("list_devices [-s] [-U uid] [-z zonename] "
+		    "[-a] -l [device]");
+		use[6] = gettext("list_devices [-s] [-U uid] [-z zonename] "
+		    "[-a] -n [device]");
+		use[7] = gettext("list_devices [-s] [-U uid] [-z zonename] "
+		    "[-a] -u [device]");
+		use[8] = gettext("list_devices [-s] -d dev_type");
 
-	switch (func) {
-		case 0:
-			(void) fprintf(stderr, "%s\n%s\n", use[0], use[1]);
-			break;
-		case 1:
-			(void) fprintf(stderr, "%s\n%s\n", use[2], use[3]);
-			break;
-		case 2:
-			(void) fprintf(stderr, "%s\n%s\n%s\n", use[4], use[5],
-			    use[6]);
-			break;
-		default:
-			(void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
-				use[0], use[1], use[2], use[3], use[4]);
+		switch (func) {
+			case 0:
+				(void) fprintf(stderr, "%s\n%s\n",
+				    use[0], use[1]);
+				break;
+			case 1:
+				(void) fprintf(stderr, "%s\n%s\n%s\n",
+				    use[2], use[3], use[4]);
+				break;
+			case 2:
+				(void) fprintf(stderr, "%s\n%s\n%s\n%s\n",
+				    use[5], use[6], use[7], use[8]);
+				break;
+			default:
+				(void) fprintf(stderr,
+				    "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+				    use[0], use[1], use[2], use[3], use[4],
+				    use[5], use[6], use[7], use[8]);
+		}
+	} else {
+		char *use[7];
+
+		use[0] = gettext("allocate [-s] [-U uname] [-F] device");
+		use[1] = gettext("allocate [-s] [-U uname] -g dev_type");
+		use[2] = gettext("deallocate [-s] [-F] device");
+		use[3] = gettext("deallocate [-s] -I");
+		use[4] = gettext("list_devices [-s] [-U uid] -l [device]");
+		use[5] = gettext("list_devices [-s] [-U uid] -n [device]");
+		use[6] = gettext("list_devices [-s] [-U uid] -u [device]");
+
+		switch (func) {
+			case 0:
+				(void) fprintf(stderr, "%s\n%s\n",
+				    use[0], use[1]);
+				break;
+			case 1:
+				(void) fprintf(stderr, "%s\n%s\n",
+				    use[2], use[3]);
+				break;
+			case 2:
+				(void) fprintf(stderr, "%s\n%s\n%s\n",
+				    use[4], use[5], use[6]);
+				break;
+			default:
+				(void) fprintf(stderr,
+				    "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+					use[0], use[1], use[2], use[3], use[4],
+					use[5], use[6]);
+		}
 	}
 	exit(1);
 }
 
-static void
+void
 print_error(int error, char *name)
 {
-	char *msg;
+	char	*msg;
+	char	msgbuf[200];
 
 	switch (error) {
-	case SYSERROR:
-		msg = gettext("Unknown System error.");
+	case ALLOCUERR:
+		msg = gettext("Specified device is allocated to another user.");
 		break;
-	case IMPORT_ERR:
-		msg = gettext(
-		    "User lacks authorization required for this operation.");
+	case CHOWNERR:
+		msg = gettext("Failed to chown.");
 		break;
-	case NODAENT:
+	case CLEANERR:
+		msg = gettext("Unable to clean up device.");
+		break;
+	case CNTDEXECERR:
 		msg = gettext(
-		    "No device allocate file entry for specified device.");
-		break;
-	case NODMAPENT:
-		msg = gettext(
-		    "No device maps file entry for specified device.");
+		    "Can't exec device-clean program for specified device.");
 		break;
-	case DACLCK:
-		msg = gettext("Concurrent operations for specified device, "
-		    "try later.");
+	case CNTFRCERR:
+		msg = gettext("Can't force deallocate specified device.");
 		break;
-	case DACACC:
+	case DACACCERR:
 		msg = gettext(
 		    "Can't access DAC file for the device specified.");
 		break;
-	case DEVLST:
+	case DAOFFERR:
 		msg = gettext(
-		    "Could not use device list for the device specified.");
+		    "Device allocation feature is not activated "
+		    "on this system.");
+		break;
+	case DAUTHERR:
+		msg = gettext("Device not allocatable.");
 		break;
-	case NALLOCU:
-		msg = gettext("Specified device is allocated to another user.");
+	case DEFATTRSERR:
+		msg = gettext("No default attributes for specified "
+		    "device type.");
 		break;
-	case NOTAUTH:
-		msg = gettext("Not authorized for specified operation.");
+	case DEVLKERR:
+		msg = gettext("Concurrent operations for specified device, "
+		    "try later.");
 		break;
-	case CNTFRC:
-		msg = gettext("Can't force deallocate specified device.");
+	case DEVLONGERR:
+		msg = gettext("Device name is too long.");
+		break;
+	case DEVNALLOCERR:
+		msg = gettext("Device not allocated.");
+		break;
+	case DEVNAMEERR:
+		msg = gettext("Device name error.");
 		break;
-	case CNTDEXEC:
-		msg = gettext(
-		    "Can't exec device-clean program for specified device.");
+	case DEVSTATEERR:
+		msg = gettext("Device specified is in allocate error state.");
 		break;
-	case NO_DEVICE:
-		msg = gettext(
-		    "Can't find a device of type requested to allocate.");
+	case DEVZONEERR:
+		msg = gettext("Can't find name of the zone to which "
+		    "device is allocated.");
 		break;
-	case DSPMISS:
+	case DSPMISSERR:
 		msg = gettext(
 		    "Device special file(s) missing for specified device.");
 		break;
-	case ALLOCERR:
-		msg = gettext("Device specified is in allocate error state.");
+	case LABELRNGERR:
+		msg = gettext(
+		    "Operation inconsistent with device's label range.");
+		break;
+	case LOGINDEVPERMERR:
+		msg = gettext("Device controlled by logindevperm(4)");
 		break;
-	case CHOWN_PERR:
-		msg = gettext("Process lacks privilege required to chown().");
+	case NODAERR:
+		msg = gettext("No entry for specified device.");
 		break;
-	case ALLOC:
+	case NODMAPERR:
+		msg = gettext("No entry for specified device.");
+		break;
+	case PREALLOCERR:
 		msg = gettext("Device already allocated.");
 		break;
-	case ALLOC_OTHER:
-		msg = gettext("Device allocated to another user.");
-		break;
-	case NALLOC:
-		msg = gettext("Device not allocated.");
-		break;
-	case AUTHERR:
-		msg = gettext("Device not allocatable.");
+	case SETACLERR:
+		msg = gettext("Failed to set ACL.");
 		break;
-	case CLEAN_ERR:
-		msg = gettext("Unable to clean up the device.");
-		break;
-	case SETACL_PERR:
-		msg = gettext("Process lacks privilege required to set ACL.");
+	case UAUTHERR:
+		msg = gettext(
+		    "User lacks authorization required for this operation.");
 		break;
-	case DEVNAME_ERR:
-		msg = gettext("Error forming device name.");
-		break;
-	case DEVNAME_TOOLONG:
-		msg = gettext("Device name is too long.");
+	case ZONEERR:
+		msg = gettext("Failed to configure device in zone.");
 		break;
 	default:
 		msg = gettext("Unknown error code.");
 		break;
 	}
 
-	(void) fprintf(stderr, "%s: %s\n", name, msg);
-	(void) fflush(stderr);
+	if (windowing) {
+		(void) snprintf(msgbuf, sizeof (msgbuf), "%s: %s\n", name, msg);
+		(void) wdwmsg(name, msgbuf);
+	} else {
+		(void) fprintf(stderr, "%s: %s\n", name, msg);
+		(void) fflush(stderr);
+	}
 }
 
 char *newenv[] = {"PATH=/usr/bin:/usr/sbin",
@@ -193,16 +260,21 @@
 int
 main(int argc, char *argv[], char *envp[])
 {
-	char	*name, *env;
-	int	func = -1, optflg = 0, error = 0, c;
-	uid_t	uid = getuid();
-	char	*uname = NULL, *device = NULL;
-	struct passwd *pw_ent;
-	int env_num = 1;	/* PATH= is 0 entry */
+	char		*name, *env;
+	int		func = -1, optflg = 0, error = 0, c;
+	zoneid_t	zoneid;
+	uid_t		uid;
+	char		*uname = NULL, *device = NULL, *zonename = NULL;
+	char		*zname;
+	char		pw_buf[NSS_BUFLEN_PASSWD];
+	struct passwd	pw_ent;
+	int 		env_num = 1;	/* PATH= is 0 entry */
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
+	system_labeled = is_system_labeled();
+
 	/*
 	 * get all enviroment variables
 	 * which affect on internationalization.
@@ -234,43 +306,75 @@
 	else
 		name++;
 
-	if (strcmp(name, "allocate") == 0)
+	if (strcmp(name, ALLOC) == 0)
 		func = 0;
-	else if (strcmp(name, "deallocate") == 0)
+	else if (strcmp(name, DEALLOC) == 0)
 		func = 1;
-	else if (strcmp(name, "list_devices") == 0)
+	else if (strcmp(name, LIST) == 0)
 		func = 2;
-	else {
-		usage(ALL);
-	}
+	else
+		usage(-1);
 
 	audit_allocate_argv(func, argc, argv);
 
+	if (system_labeled) {
+		/*
+		 * allocate, deallocate, list_devices run in
+		 * global zone only.
+		 */
+		zoneid = getzoneid();
+		if (zoneid != GLOBAL_ZONEID)
+			exit(GLOBALERR);
+		zname = GLOBAL_ZONENAME;
+		/*
+		 * check if device allocation is activated.
+		 */
+		if (da_is_on() == 0) {
+			(void) fprintf(stderr, "%s%s",
+			    gettext("Turn device allocation on"),
+			    gettext(" to use this feature.\n"));
+			exit(DAOFFERR);
+		}
+	}
+
 	if (func == 0) {	/* allocate */
-		while ((c = getopt(argc, argv, "sU:Fg")) != -1) {
+		while ((c = getopt(argc, argv, "gswz:FU:")) != -1) {
 			switch (c) {
+			case 'g':
+				optflg |= TYPE;
+				break;
 			case 's':
 				optflg |= SILENT;
 				break;
+			case 'w':
+				if (system_labeled) {
+					optflg |= WINDOWING;
+					windowing = 1;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'z':
+				if (system_labeled) {
+					optflg |= ZONENAME;
+					zonename = optarg;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'F':
+				optflg |= FORCE;
+				break;
 			case 'U':
 				optflg |= USERNAME;
 				uname = optarg;
 				break;
-			case 'g':
-				optflg |= TYPE;
-				break;
-			case 'F':
-				optflg |= FORCE;
-				break;
 			case '?':
 			default :
 				usage(func);
 			}
 		}
 
-		if ((optflg & TYPE) && (optflg & FORCE))
-			usage(func);
-
 		/*
 		 * allocate(1) must be supplied with one device argument
 		 */
@@ -282,11 +386,33 @@
 	}
 
 	else if (func == 1) {	/* deallocate */
-		while ((c = getopt(argc, argv, "sFI")) != -1) {
+		while ((c = getopt(argc, argv, "gswz:FI")) != -1) {
 			switch (c) {
+			case 'g':
+				if (system_labeled)
+					optflg |= TYPE;
+				else
+					usage(func);
+				break;
 			case 's':
 				optflg |= SILENT;
 				break;
+			case 'w':
+				if (system_labeled) {
+					optflg |= WINDOWING;
+					windowing = 1;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'z':
+				if (system_labeled) {
+					optflg |= ZONENAME;
+					zonename = optarg;
+				} else {
+					usage(func);
+				}
+				break;
 			case 'F':
 				optflg |= FORCE;
 				break;
@@ -302,6 +428,9 @@
 		if ((optflg & FORCE) && (optflg & FORCE_ALL))
 			usage(func);
 
+		if (system_labeled && ((optflg & FORCE_ALL) && (optflg & TYPE)))
+			usage(func);
+
 		/*
 		 * deallocate(1) must be supplied with one device
 		 * argument unless the '-I' argument is supplied
@@ -320,35 +449,86 @@
 	}
 
 	else if (func == 2) {	/* list_devices */
-		while ((c = getopt(argc, argv, "sU:lnu")) != -1) {
+		while ((c = getopt(argc, argv, "adlnsuwz:U:")) != -1) {
 			switch (c) {
+			case 'a':
+				if (system_labeled) {
+					/*
+					 * list auths, cleaning programs,
+					 * labels.
+					 */
+					optflg |= LISTATTRS;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'd':
+				if (system_labeled) {
+					/*
+					 * list devalloc_defaults
+					 */
+					optflg |= LISTDEFS;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'l':
+				optflg |= LISTALL;
+				break;
+			case 'n':
+				optflg |= LISTFREE;
+				break;
 			case 's':
 				optflg |= SILENT;
 				break;
+			case 'u':
+				optflg |= LISTALLOC;
+				break;
+			case 'w':
+				if (system_labeled) {
+					/*
+					 * Private interface for use by
+					 * list_devices GUI
+					 */
+					optflg |= WINDOWING;
+				} else {
+					usage(func);
+				}
+				break;
+			case 'z':
+				if (system_labeled) {
+					optflg |= ZONENAME;
+					zonename = optarg;
+				} else {
+					usage(func);
+				}
+				break;
 			case 'U':
 				optflg |= USERID;
 				uid = atoi(optarg);
 				break;
-			case 'l':
-				optflg |= LIST;
-				break;
-			case 'n':
-				optflg |= FREE;
-				break;
-			case 'u':
-				optflg |= CURRENT;
-				break;
 			case '?':
 			default :
 				usage(func);
 			}
 		}
 
-		if (((optflg & LIST) && (optflg & FREE)) ||
-		    ((optflg & LIST) && (optflg & CURRENT)) ||
-		    ((optflg & FREE) && (optflg & CURRENT)) ||
-		    (!(optflg & (LIST | FREE | CURRENT))))
+		if (system_labeled) {
+			if (((optflg & LISTALL) && (optflg & LISTFREE)) ||
+			    ((optflg & LISTALL) && (optflg & LISTALLOC)) ||
+			    ((optflg & LISTFREE) && (optflg & LISTALLOC)) ||
+			    ((optflg & LISTDEFS) &&
+			    (optflg & (LISTATTRS | LISTALL | LISTFREE |
+			    LISTALLOC | USERID | WINDOWING | ZONENAME))) ||
+			    (!(optflg & (LISTALL | LISTFREE | LISTALLOC |
+			    LISTDEFS | WINDOWING))))
+				usage(func);
+		} else if (((optflg & LISTALL) && (optflg & LISTFREE)) ||
+		    ((optflg & LISTALL) && (optflg & LISTALLOC)) ||
+		    ((optflg & LISTFREE) && (optflg & LISTALLOC)) ||
+		    (!(optflg & (LISTALL | LISTFREE | LISTALLOC)))) {
 			usage(func);
+		}
 
 		/*
 		 * list_devices(1) takes an optional device argument
@@ -363,30 +543,46 @@
 	}
 
 	if (optflg & USERNAME) {
-		if ((pw_ent = getpwnam(uname)) == NULL) {
-			(void) fprintf(stderr, gettext(
-			    "Invalid user name -- %s -- \n"), uname);
+		if (getpwnam_r(uname, &pw_ent, pw_buf, sizeof (pw_buf)) ==
+		    NULL) {
+			(void) fprintf(stderr,
+			    gettext("Invalid user name -- %s -- \n"), uname);
 			exit(1);
 		}
-		uid = pw_ent->pw_uid;
+		uid = pw_ent.pw_uid;
+	} else if (optflg & USERID) {
+		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
+			(void) fprintf(stderr,
+			    gettext("Invalid user ID -- %d -- \n"), uid);
+			exit(1);
+		}
+		uid = pw_ent.pw_uid;
+	} else {
+		/*
+		 * caller's uid is the default if no user specified.
+		 */
+		uid = getuid();
 	}
 
-	if (optflg & USERID) {
-		if ((pw_ent = getpwuid(uid)) == NULL) {
-			(void) fprintf(stderr, gettext(
-			    "Invalid user ID -- %d -- \n"), uid);
+	/*
+	 * global zone is the default if no zonename specified.
+	 */
+	if (zonename == NULL) {
+		zonename = zname;
+	} else {
+		if (zone_get_id(zonename, &zoneid) != 0) {
+			(void) fprintf(stderr,
+			    gettext("Invalid zone name -- %s -- \n"), zonename);
 			exit(1);
 		}
-		uid = pw_ent->pw_uid;
 	}
 
-	if (func == 0) {
-		error = allocate(optflg, uid, device);
-	} else if (func == 1) {
-		error = deallocate(optflg, uid, device);
-	} else if (func == 2) {
-		error = list_devices(optflg, uid, device);
-	}
+	if (func == 0)
+		error = allocate(optflg, uid, device, zonename);
+	else if (func == 1)
+		error = deallocate(optflg, uid, device, zonename);
+	else if (func == 2)
+		error = list_devices(optflg, uid, device, zonename);
 
 	(void) audit_allocate_record(error);
 
@@ -398,3 +594,41 @@
 
 	return (0);
 }
+
+/*
+ * Display error message via /etc/security/lib/wdwmsg script
+ */
+static int
+wdwmsg(char *name, char *msg)
+{
+	pid_t child_pid;
+	pid_t wait_pid;
+	int child_status;
+
+	/* Fork a child */
+	switch (child_pid = fork()) {
+	case -1:	/* FAILURE */
+		return (-1);
+		break;
+
+	case 0:		/* CHILD */
+		(void) execl("/etc/security/lib/wdwmsg", "wdwmsg", msg,
+		    name, "OK", NULL);
+		/* If exec failed, send message to stderr */
+		(void) fprintf(stderr, "%s", msg);
+		return (-1);
+
+	default:	/* PARENT */
+		/* Wait for child to exit */
+		wait_pid = waitpid(child_pid, &child_status, 0);
+		if ((wait_pid < 0) && (errno == ECHILD))
+			return (0);
+		if ((wait_pid < 0) || (wait_pid != child_pid))
+			return (-1);
+		if (WIFEXITED(child_status))
+			return (WEXITSTATUS(child_status));
+		if (WIFSIGNALED(child_status))
+			return (WTERMSIG(child_status));
+		return (0);
+	}
+}
--- a/usr/src/cmd/allocate/allocate.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/allocate.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -34,59 +34,58 @@
 #endif
 
 /* Option Flags */
-#define	SILENT		0001	/* -s */
-#define	USERID		0002	/* -U <uid> for list_devices(1) */
-#define	LIST		0004	/* -l */
-#define	FREE		0010	/* -n */
-#define	CURRENT 	0020	/* -u */
-#define	FORCE		0040	/* -F */
-#define	FORCE_ALL 	0100	/* -I */
-#define	TYPE		0200	/* -g */
-#define	USERNAME	0400	/* -U <username> for allocate(1) */
+#define	LISTATTRS	0x00000001	/* -a */
+#define	LISTDEFS	0x00000002	/* -d */
+#define	TYPE		0x00000004	/* -g */
+#define	LISTALL		0x00000008	/* -l */
+#define	LISTFREE	0x00000010	/* -n */
+#define	SILENT		0x00000020	/* -s */
+#define	LISTALLOC 	0x00000040	/* -u */
+#define	WINDOWING	0x00000080	/* -w */
+#define	ZONENAME	0x00000100	/* -z */
+#define	BOOT		0x00000200	/* -B */
+#define	FORCE		0x00000400	/* -F */
+#define	FORCE_ALL 	0x00000800	/* -I */
+#define	USERID		0x00001000	/* -U for list_devices */
+#define	USERNAME	0x00002000	/* -U for allocate */
 
 /* Misc. */
 
-#define	ALL	-1
+#define	CLEAN_MOUNT		11	/* Also defined in disk_clean.sh */
 
-/* Error returns start at 4 */
-#define	SYSERROR	4
-#define	DACLCK		5
-#define	DACACC		6
-#define	DEVLST		7
-#define	NALLOCU		8
-#define	NOTAUTH		9
-#define	CNTFRC		10
-#define	CNTDEXEC	11
-#define	NO_DEVICE	12
-#define	DSPMISS		13
-#define	ALLOCERR	14
-#define	IMPORT_ERR	15
-#define	NODAENT		16
-#define	NODMAPENT	17
-#define	SETACL_PERR	18
-#define	CHOWN_PERR	19
-#define	ALLOC		20
-#define	ALLOC_OTHER	21
-#define	NALLOC		22
-#define	AUTHERR		23
-#define	CLEAN_ERR	24
-#define	DEVNAME_ERR	25
-#define	DEVNAME_TOOLONG	26
+#define	ALLOCUERR		1
+#define	CHOWNERR		2
+#define	CLEANERR		3
+#define	CNTDEXECERR		4
+#define	CNTFRCERR		5
+#define	DACACCERR		6
+#define	DAOFFERR		7
+#define	DAUTHERR		8
+#define	DEFATTRSERR		9
+#define	DEVLKERR		10
+#define	DEVLONGERR		11
+#define	DEVNALLOCERR		12
+#define	DEVNAMEERR		13
+#define	DEVSTATEERR		14
+#define	DEVZONEERR		15
+#define	DSPMISSERR		16
+#define	GLOBALERR		17
+#define	LABELRNGERR		18
+#define	LOGINDEVPERMERR		19
+#define	NODAERR			20
+#define	NODMAPERR		21
+#define	PREALLOCERR		22
+#define	SETACLERR		23
+#define	UAUTHERR		24
+#define	ZONEERR			25
 
-/* Tunable Parameters */
-#define	DEV_DIR		"/dev"
-#define	DAC_DIR		"/etc/security/dev"
-#define	SECLIB		"/etc/security/lib"
-#define	ALLOC_MODE	0600
-#define	DEALLOC_MODE    0000
 #define	ALLOC_ERR_MODE  0100
-#define	ALLOC_UID	(uid_t)0	/* root */
-#define	ALLOC_GID	(gid_t)1	/* other */
+#define	ALLOC_INVALID	0700
 
 /* Functions */
-extern int allocate(int optflg, uid_t uid, char *device);
-extern int deallocate(int optflg, uid_t uid, char *device);
-extern int list_devices(int optflg, uid_t uid, char *device);
+extern int allocate(int optflg, uid_t uid, char *device, char *zonename);
+extern int deallocate(int optflg, uid_t uid, char *device, char *zonename);
+extern int list_devices(int optflg, uid_t uid, char *device, char *zonename);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/cmd/allocate/allocate3.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/allocate3.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -38,11 +38,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
-
 #include <bsm/devices.h>
-#include <bsm/audit_uevents.h>
-
+#include <sys/acl.h>
+#include <tsol/label.h>
+#include <syslog.h>
+#include <limits.h>
+#include <user_attr.h>
+#include <secdb.h>
+#include <sys/mkdev.h>
 #include <sys/acl.h>
 #include <sys/file.h>
 #include <sys/procfs.h>
@@ -52,198 +57,510 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-
+#include <utime.h>
+#include <libgen.h>
+#include <zone.h>
+#include <nss_dbdefs.h>
+#include <bsm/devalloc.h>
 #include "allocate.h"
 
-#ifdef	DEBUG
+extern void print_error(int, char *);
+
+#if	defined(DEBUG) || defined(lint)
 #define	dprintf(s, a) (void) fprintf(stderr, s, a)
 #define	dperror(s) perror(s)
 #else	/* !DEBUG */
-#define	dprintf(s, a)
-#define	dperror(s)
+#define	dprintf(s, a)	0
+#define	dperror(s)	0
 #endif	/* DEBUG */
 
-#define	EXIT(number) { \
-	if (optflg & FORCE) \
-		error = number; \
-	else \
-		return (number); \
-}
+#define	DEV_ERRORED(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
+#define	DEV_INVALID(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_INVALID)
+#define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != ALLOC_UID || \
+			!(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
+			DEV_ERRORED(sbuf) || DEV_INVALID(sbuf)))
 
-#define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != ALLOC_UID || \
-				((sbuf).st_mode & ~S_IFMT) == ALLOC_MODE)
+#define	ALLOC_CLEAN		"-A"
+#define	DEALLOC_CLEAN		"-D"
+#define	DAC_DIR			"/etc/security/dev"
+#define	DEVICE_AUTH_SEPARATOR	","
+#define	LOCALDEVICE		"/dev/console"
+#define	PROCFS			"/proc/"
+#define	SFF_NO_ERROR		0x1
 
-#define	DEVICE_AUTH_SEPARATOR	","
-#define	PROCFS	"/proc/"
+#define	ALLOC_BY_NONE		-1
+#define	CHECK_DRANGE		1
+#define	CHECK_URANGE		2
+#define	CHECK_ZLABEL		3
 
 extern void audit_allocate_list(char *);
 extern void audit_allocate_device(char *);
 
+extern int	system_labeled;
 extern char	*newenv[];
 
+struct state_file {
+	int	sf_flags;
+	char	sf_path[MAXPATHLEN];
+};
+
+struct file_info {
+	struct stat	fi_stat;
+	char		*fi_message;
+};
+
+struct zone_path {
+	int	count;
+	char	**path;
+};
+
+struct devnames {
+	char **dnames;
+};
+
+static int _dev_file_name(struct state_file *, devmap_t *);
+static int lock_dev(char *);
+static int _check_label(devalloc_t *, char *, uid_t, int);
+static int create_znode(char *, struct zone_path *, devmap_t *);
+static int remove_znode(char *, devmap_t *);
+static int update_device(char **, char *, int);
+
 /*
- * Checks if the specified user has any of the authorizations in the
- * list of authorizations
+ * checks if the invoking user is local to the device
  */
-
-static int
-is_authorized(char *auth_list, uid_t uid)
+/*ARGSUSED*/
+int
+_is_local(uid_t uid)
 {
-	char	*auth;
-	struct passwd *pw;
+	struct stat	statbuf;
 
-	pw = getpwuid(uid);
-	if (pw == NULL) {
-		dprintf("Can't get user info for uid=%d\n", (int)uid);
-		return (0);
-	}
+	if (stat(LOCALDEVICE, &statbuf) == 0 &&
+	    statbuf.st_uid == uid)
+		return (1);
 
-	auth = strtok(auth_list, DEVICE_AUTH_SEPARATOR);
-	while (auth != NULL) {
-		if (chkauthattr(auth, pw->pw_name))
-			return (1);
-		auth = strtok(NULL, DEVICE_AUTH_SEPARATOR);
-	}
 	return (0);
 }
 
-static int
-check_devs(char *list)
+/*
+ * Checks if the user with the specified uid has the specified authorization
+ */
+int
+_is_authorized(char *auths, uid_t uid)
 {
-	char	*file;
+	char		*dcp, *authlist, *lasts;
+	char		pw_buf[NSS_BUFLEN_PASSWD];
+	struct passwd	pw_ent;
+
+	/*
+	 * first, the easy cases
+	 */
+	if (strcmp(auths, "@") == 0)
+		return (1);
+	if (strcmp(auths, "*") == 0)
+		return (ALLOC_BY_NONE);
+	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
+		return (0);
+	if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL)
+		return (chkauthattr(auths, pw_ent.pw_name));
+	authlist = strdup(auths);
+	if (authlist == NULL)
+		return (0);
+	for (dcp = authlist;
+	    (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL;
+	    dcp = NULL) {
+		if (chkauthattr(dcp, pw_ent.pw_name))
+			break;
+	}
+	free(authlist);
+
+	return (dcp != NULL);
+}
+
+/*
+ * Checks if the specified user has authorization for the device
+ */
+int
+_is_dev_authorized(devalloc_t *da, uid_t uid)
+{
+	int	ares;
+	char	*auth_list, *dcp, *subauth = NULL;
 
-	file = strtok(list, " ");
-	while (file != NULL) {
+	auth_list = da->da_devauth;
+	if (auth_list == NULL)
+		return (0);
+	dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT);
+	if (dcp == NULL)
+		return (_is_authorized(auth_list, uid));
+	if (_is_local(uid)) {
+		/* the local authorization is before the separator */
+		ares = dcp - auth_list;
+		subauth = malloc(ares + 1);
+		if (subauth == NULL)
+			return (0);
+		(void) strlcpy(subauth, auth_list, (ares + 1));
+		auth_list = subauth;
+	} else
+		auth_list = dcp + 1;
+	ares = _is_authorized(auth_list, uid);
+	if (subauth != NULL)
+		free(subauth);
+
+	return (ares);
+}
+
+int
+check_devs(devmap_t *dm)
+{
+	int	status = 0;
+	char	**file;
 
-		if (access(file, F_OK) == -1) {
-			dprintf("Unable to access file %s\n", file);
-			return (-1);
+	if (dm->dmap_devarray == NULL)
+		return (NODMAPERR);
+	for (file = dm->dmap_devarray; *file != NULL; file++) {
+		if ((status = access(*file, F_OK)) == -1) {
+			dprintf("Unable to access file %s\n", *file);
+			break;
 		}
-		file = strtok(NULL, " ");
 	}
+
+	return (status);
+}
+
+int
+print_da_defs(da_defs_t *da_defs)
+{
+	char	optbuf[BUFSIZ];
+	char	*p = NULL;
+
+	if (da_defs->devopts == NULL) {
+		dprintf("No default attributes for %s\n", da_defs->devtype);
+		return (DEFATTRSERR);
+	}
+	(void) printf("dev_type=%s\n", da_defs->devtype);
+	if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN,
+	    KV_TOKEN_DELIMIT) == 0) {
+		if (p = rindex(optbuf, ':'))
+			*p = '\0';
+		(void) printf("\t%s\n", optbuf);
+	}
+
 	return (0);
 }
 
-static void
-print_dev(devmap_t *dev_list)
+void
+print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm,
+    struct file_info *fip)
 {
-	char	*file;
+	char	*p = NULL;
+	char	optbuf[BUFSIZ];
 
-	(void) printf(gettext("device: %s "), dev_list->dmap_devname);
-	(void) printf(gettext("type: %s "), dev_list->dmap_devtype);
-	(void) printf(gettext("files: "));
+	(void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER);
+	(void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER);
+	(void) printf("auths=%s%s",
+	    (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER);
+	(void) printf("clean=%s%s",
+	    (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER);
+	if (da->da_devopts != NULL) {
+		if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf),
+		    KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) {
+			if (p = rindex(optbuf, ':'))
+				*p = '\0';
+			(void) printf("%s", optbuf);
+		}
+	}
+	(void) printf("%s", KV_DELIMITER);
+	if (optflag & WINDOWING) {
+		if (DEV_INVALID(fip->fi_stat))
+			(void) printf("owner=/INVALID:%s%s", fip->fi_message,
+			    KV_DELIMITER);
+		else if (DEV_ERRORED(fip->fi_stat))
+			(void) printf("owner=/ERROR%s", KV_DELIMITER);
+		else if (!DEV_ALLOCATED(fip->fi_stat))
+			(void) printf("owner=/FREE%s", KV_DELIMITER);
+		else
+			(void) printf("owner=%ld%s", fip->fi_stat.st_uid,
+			    KV_DELIMITER);
+	}
+	(void) printf("files=%s", dm->dmap_devlist);
+	(void) printf("\n");
+}
 
-	file = strtok(dev_list->dmap_devlist, " ");
-	while (file != NULL) {
-		(void) printf("%s ", file);
-		file = strtok(NULL, " ");
+void
+print_dev(devmap_t *dm)
+{
+	char	**file;
+
+	(void) printf(gettext("device: %s "), dm->dmap_devname);
+	(void) printf(gettext("type: %s "), dm->dmap_devtype);
+	(void) printf(gettext("files:"));
+	file = dm->dmap_devarray;
+	if (file != NULL) {
+		for (; *file != NULL; file++)
+			(void) printf(" %s", *file);
 	}
 	(void) printf("\n");
 }
 
-static int
-list_device(int optflg, uid_t uid, char *device)
+/* ARGSUSED */
+int
+_list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename)
 {
-	devalloc_t *dev_ent;
-	devmap_t *dev_list;
-	char	file_name[MAXPATHLEN];
-	struct	stat stat_buf;
-	char	*list;
-	int	bytes_formated;
-
-	if ((dev_ent = getdanam(device)) == NULL) {
-		if ((dev_list = getdmapdev(device)) == NULL) {
-			dprintf("Unable to find %s in the allocate database\n",
-			    device);
-			return (NODMAPENT);
-		} else if ((dev_ent = getdanam(dev_list->dmap_devname)) ==
-		    NULL) {
-			dprintf("Unable to find %s in the allocate database\n",
-			    device);
-			return (NODAENT);
-		}
-	} else if ((dev_list = getdmapnam(device)) == NULL) {
-		dprintf("Unable to find %s in the allocate database\n", device);
-		return (NODMAPENT);
-	}
+	int			bytes = 0;
+	int			error = 0;
+	int			is_authorized = 0;
+	char			*fname = NULL;
+	char			file_name[MAXPATHLEN];
+	devmap_t		*dm;
+	struct file_info	fi;
+	struct state_file	sf;
 
-	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
-	    dev_ent->da_devname);
-	if (bytes_formated <= 0) {
-		return (DEVNAME_ERR);
-	} else if (bytes_formated >= MAXPATHLEN) {
-		dprintf("device name %s is too long.\n", dev_ent->da_devname);
-		return (DEVNAME_TOOLONG);
+	setdmapent();
+	if ((dm = getdmapnam(da->da_devname)) == NULL) {
+		enddmapent();
+		dprintf("Unable to find %s in the maps database\n",
+		    da->da_devname);
+		return (NODMAPERR);
+	}
+	enddmapent();
+	if (system_labeled) {
+		if ((error = _dev_file_name(&sf, dm)) != 0) {
+			freedmapent(dm);
+			dprintf("Unable to find %s device files\n",
+			    da->da_devname);
+			error = NODMAPERR;
+			goto out;
+		}
+		fname = sf.sf_path;
+	} else {
+		bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
+		    da->da_devname);
+		if (bytes <= 0) {
+			error = DEVNAMEERR;
+			goto out;
+		} else if (bytes >= MAXPATHLEN) {
+			dprintf("device name %s is too long.\n",
+			    da->da_devname);
+			error = DEVLONGERR;
+			goto out;
+		}
+		fname = file_name;
+	}
+	if (stat(fname, &fi.fi_stat) != 0) {
+		dprintf("Unable to stat %s\n", fname);
+		dperror("Error:");
+		error = DACACCERR;
+		goto out;
 	}
-
-	if (stat(file_name, &stat_buf)) {
-		dprintf("Unable to stat %s\n", file_name);
-		dperror("Error:");
-		return (DACACC);
+	if (optflag & USERID)
+		is_authorized = 1;
+	else
+		is_authorized = _is_dev_authorized(da, uid);
+	if (optflag & LISTFREE) {	/* list_devices -n */
+		/*
+		 * list all free devices
+		 */
+		if (DEV_ALLOCATED(fi.fi_stat)) {
+				error = PREALLOCERR;
+				goto out;
+		}
+		if (system_labeled) {
+			/*
+			 * for this free device, check if -
+			 * 1. user has authorization to allocate
+			 * 2. the zone label is within the label range of the
+			 *    device
+			 */
+			if (is_authorized == ALLOC_BY_NONE) {
+				error = DAUTHERR;
+				goto out;
+			} else if (is_authorized == 0) {
+				error = UAUTHERR;
+				goto out;
+			}
+			if (_check_label(da, zonename, uid,
+			    CHECK_DRANGE) != 0) {
+				error = LABELRNGERR;
+				goto out;
+			}
+		}
+	} else if (optflag & LISTALLOC) {	/*  list_devices -u */
+		/*
+		 * list all allocated devices
+		 */
+		if (!DEV_ALLOCATED(fi.fi_stat)) {
+			error = DEVNALLOCERR;
+			goto out;
+		}
+		if (fi.fi_stat.st_uid != uid) {
+			error = DEVSTATEERR;
+			goto out;
+		}
+		if (system_labeled) {
+			/*
+			 * check if the zone label equals the label at which
+			 * the device is allocated.
+			 */
+			if (_check_label(da, zonename, uid,
+			    CHECK_ZLABEL) != 0) {
+				error = LABELRNGERR;
+				goto out;
+			}
+		}
+	} else if (optflag & LISTALL) {		/* list_devices -l */
+		/*
+		 * list all devices - free and allocated - available
+		 */
+		if (DEV_ALLOCATED(fi.fi_stat)) {
+			if (optflag & WINDOWING &&
+			    (is_authorized == ALLOC_BY_NONE)) {
+				/*
+				 * don't complain if we're here for the GUI.
+				 */
+				error = 0;
+			} else if (fi.fi_stat.st_uid != uid) {
+				if (!(optflag & WINDOWING)) {
+					error = ALLOCUERR;
+					goto out;
+				}
+			}
+			if (system_labeled && !(optflag & WINDOWING)) {
+				/*
+				 * if we're not displaying in the GUI,
+				 * check if the zone label equals the label
+				 * at which the device is allocated.
+				 */
+				if (_check_label(da, zonename, uid,
+				    CHECK_ZLABEL) != 0) {
+					error = LABELRNGERR;
+					goto out;
+				}
+			}
+		} else if (system_labeled && !(optflag & WINDOWING)) {
+			/*
+			 * if we're not displaying in the GUI,
+			 * for this free device, check if -
+			 * 1. user has authorization to allocate
+			 * 2. the zone label is within the label range of the
+			 *    device
+			 */
+			if (is_authorized == ALLOC_BY_NONE) {
+				error = DAUTHERR;
+				goto out;
+			} else if (is_authorized == 0) {
+				error = UAUTHERR;
+				goto out;
+			}
+			if (_check_label(da, zonename, uid,
+			    CHECK_DRANGE) != 0) {
+				error = LABELRNGERR;
+				goto out;
+			}
+		}
 	}
-
-	if ((optflg & FREE) && DEV_ALLOCATED(stat_buf))
-		return (ALLOC);
+	if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) {
+		error = DEVSTATEERR;
+		goto out;
+	}
+	if (check_devs(dm) == -1) {
+		error = DSPMISSERR;
+		goto out;
+	}
+	if (optflag & LISTATTRS)
+		print_dev_attrs(optflag, da, dm, &fi);
+	else
+		print_dev(dm);
 
-	if ((optflg & LIST) && DEV_ALLOCATED(stat_buf) &&
-	    (stat_buf.st_uid != uid))
-		return (ALLOC_OTHER);
-
-	if ((optflg & CURRENT) && (stat_buf.st_uid != uid))
-		return (NALLOC);
-
-	if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
-		return (ALLOCERR);
+	error = 0;
 
-	if ((list = strdup(dev_list->dmap_devlist)) == NULL)
-		return (SYSERROR);
-
-	if (check_devs(list) == -1) {
-		free(list);
-		return (DSPMISS);
-	}
-
-	print_dev(dev_list);
-
-	free(list);
-	return (0);
+out:
+	freedmapent(dm);
+	return (error);
 }
 
+/* ARGSUSED */
 int
-list_devices(int optflg, uid_t uid, char *device)
+list_devices(int optflag, uid_t uid, char *device, char *zonename)
 {
-	DIR   * dev_dir;
-	struct dirent *dac_file;
-	int	error = 0, ret_code = 1;
+	int		error = 0;
+	da_defs_t	*da_defs;
+	devalloc_t	*da;
 
-	if (optflg & USERID) {
-		if (!is_authorized(DEVICE_REVOKE_AUTH, getuid()))
-			return (NOTAUTH);
+	if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) {
+		/*
+		 * Private interface for GUI.
+		 */
+		(void) lock_dev(NULL);
+		(void) puts(DA_DB_LOCK);
+		return (0);
+	}
+	if (optflag & USERID) {
+		/*
+		 * we need device.revoke to list someone else's devices
+		 */
+		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
+			return (UAUTHERR);
+	}
+	if (system_labeled) {
+		if (!(optflag & USERID) &&
+		    !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid))
+			/*
+			 * we need device.allocate to list our devices
+			 */
+			return (UAUTHERR);
+		if (optflag & LISTDEFS) {
+			/*
+			 * list default attrs from devalloc_defaults
+			 */
+			setdadefent();
+			if (device) {
+				/*
+				 * list default attrs for this device type
+				 */
+				da_defs = getdadeftype(device);
+				if (da_defs == NULL) {
+					enddadefent();
+					dprintf("No default attributes for "
+					    "%s\n", device);
+					return (DEFATTRSERR);
+				}
+				error = print_da_defs(da_defs);
+				freedadefent(da_defs);
+			} else {
+				/*
+				 * list everything in devalloc_defaults
+				 */
+				while ((da_defs = getdadefent()) != NULL) {
+					(void) print_da_defs(da_defs);
+					freedadefent(da_defs);
+				}
+			}
+			enddadefent();
+			return (error);
+		}
 	}
 	setdaent();
-
 	if (device) {
-		return (list_device(optflg, uid, device));
-	}
-
-	if ((dev_dir = opendir(DAC_DIR)) == NULL) {
-
-		dperror("Can't open DAC_DIR");
-		return (DACACC);
-	}
-
-	while ((dac_file = readdir(dev_dir)) != NULL) {
-		if ((strcmp(dac_file->d_name, ".") == 0) ||
-		    (strcmp(dac_file->d_name, "..") == 0)) {
-			continue;
-		} else {
-			error = list_device(optflg, uid, dac_file->d_name);
-			ret_code = ret_code ? error : ret_code;
+		/*
+		 * list this device
+		 */
+		if ((da = getdanam(device)) == NULL) {
+			enddaent();
+			return (NODAERR);
+		}
+		error = _list_device(optflag, uid, da, zonename);
+		freedaent(da);
+	} else {
+		/*
+		 * list all devices
+		 */
+		while ((da = getdaent()) != NULL) {
+			(void) _list_device(optflag, uid, da, zonename);
+			freedaent(da);
 		}
 	}
-	(void) closedir(dev_dir);
 	enddaent();
-	return (ret_code);
+
+	return (error);
 }
 
 /*
@@ -251,24 +568,41 @@
  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
  * and discards any existing ACL.
  */
-
-static int
-newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
+int
+_newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
 {
-	int		err = 0;
+	int	err = 0;
 
-	do {
+	if (mode == ALLOC_MODE) {
 		if (chown(file, owner, group) == -1) {
-			dperror("newdac, unable to chown");
-			err = CHOWN_PERR;
+			dperror("newdac: unable to chown");
+			err = CHOWNERR;
+		}
+	} else do {
+		if (chown(file, owner, group) == -1) {
+			dperror("newdac: unable to chown");
+			err = CHOWNERR;
 		}
 	} while (fdetach(file) == 0);
 
-	err = acl_strip(file, owner, group, (mode_t)mode);
+	if (err)
+		return (err);
+
+	if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
+		/*
+		 * This could be a SunRay device that is in /tmp.
+		 */
+		if (chmod(file, mode) == -1) {
+			dperror("newdac: unable to chmod");
+			err = SETACLERR;
+		}
+	} else {
+		err = acl_strip(file, owner, group, (mode_t)mode);
+	}
 
 	if (err != 0) {
-		dperror("newdac, unable to setacl");
-		err = SETACL_PERR;
+		dperror("newdac: unable to setacl");
+		err = SETACLERR;
 	}
 
 	return (err);
@@ -277,41 +611,60 @@
 static int
 lock_dev(char *file)
 {
-	int	fd;
+	int	lockfd = -1;
 
+	if ((file == NULL) || system_labeled)
+		file = DA_DEV_LOCK;
 	dprintf("locking %s\n", file);
-	if ((fd = open(file, O_RDWR)) == -1) {
-		dperror("lock_dev, cannot open DAC file");
-		return (DACACC);
+	if ((lockfd = open(file, O_RDWR | O_CREAT, 0600)) == -1) {
+		dperror("lock_dev: cannot open lock file");
+		return (DEVLKERR);
 	}
-
-	if (lockf(fd, F_TLOCK, 0) == -1) {
-		dperror("lock_dev, cannot set lock");
-		return (DACLCK);
+	if (lockf(lockfd, F_TLOCK, 0) == -1) {
+		dperror("lock_dev: cannot set lock");
+		return (DEVLKERR);
 	}
 
 	return (0);
 }
 
-static int
-mk_alloc(char *list, uid_t uid)
+int
+mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath)
 {
-	char	*file;
-	int	err;
-
-	file = strtok(list, " ");
-	while (file != NULL) {
+	int	i;
+	int	error = 0;
+	char	**file;
+	gid_t	gid = getgid();
+	mode_t	mode = ALLOC_MODE;
 
-		dprintf("Allocating %s\n", file);
-		if ((err = newdac(file, uid, getgid(), ALLOC_MODE)) != 0) {
-			(void) newdac(file, ALLOC_UID, ALLOC_GID,
+	file = list->dmap_devarray;
+	if (file == NULL)
+		return (NODMAPERR);
+	for (; *file != NULL; file++) {
+		dprintf("Allocating %s\n", *file);
+		if ((error = _newdac(*file, uid, gid, mode)) != 0) {
+			(void) _newdac(*file, ALLOC_ERRID, ALLOC_GID,
 			    ALLOC_ERR_MODE);
-			return (err);
+			break;
 		}
+	}
+	if (system_labeled && zpath->count && (error == 0)) {
+		/*
+		 * mark as allocated any new device nodes that we
+		 * created in local zone
+		 */
+		for (i = 0; i < zpath->count; i++) {
+			dprintf("Allocating %s\n", zpath->path[i]);
+			if ((error = _newdac(zpath->path[i], uid, gid,
+			    mode)) != 0) {
+				(void) _newdac(zpath->path[i], ALLOC_ERRID,
+				    ALLOC_GID, ALLOC_ERR_MODE);
+				break;
+			}
+		}
+	}
 
-		file = strtok(NULL, " ");
-	}
-	return (0);
+	return (error);
 }
 
 /*
@@ -319,33 +672,32 @@
  * because "/usr/sbin/fuser -k file" kills all processes
  * working with the file, even "vold" (bug #4095152).
  */
-static int
-mk_revoke(int optflg, char *file)
+int
+mk_revoke(int optflag, char *file)
 {
-	char buf[MAXPATHLEN];
-	int r = 0, p[2], fp, lock;
-	FILE *ptr;
-	prpsinfo_t info;
-	pid_t pid, c_pid;
+	int		r = 0, p[2], fp, lock;
+	int		fuserpid;
+	char		buf[MAXPATHLEN];
+	FILE		*ptr;
+	pid_t		c_pid;
+	prpsinfo_t	info;
 
 	(void) strcpy(buf, PROCFS);
-
 	/*
-	 * vfork() and execle() just to make the same output
+	 * vfork() and execl() just to make the same output
 	 * as before fixing of bug #4095152.
 	 * The problem is that the "fuser" command prints
 	 * one part of output into stderr and another into stdout,
 	 * but user sees them mixed. Of course, better to change "fuser"
 	 * or to intercept and not to print its output.
 	 */
-	if (!(optflg & SILENT)) {
+	if (!(optflag & SILENT)) {
 		c_pid = vfork();
 		if (c_pid == -1)
 			return (-1);
 		if (c_pid == 0) {
 			dprintf("first exec fuser %s\n", file);
-			(void) execle("/usr/sbin/fuser", "fuser", file, NULL,
-			    newenv);
+			(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
 			dperror("first exec fuser");
 			_exit(1);
 		}
@@ -355,21 +707,18 @@
 		if (WEXITSTATUS(lock) != 0)
 			return (-1);
 	}
-	dprintf("first continuing c_pid=%d\n", c_pid);
-
+	dprintf("first continuing c_pid=%d\n", (int)c_pid);
 	if (pipe(p)) {
 		dperror("pipe");
 		return (-1);
 	}
-
-	/* vfork() and execle() to catch output and to process it */
+	/* vfork() and execl() to catch output and to process it */
 	c_pid = vfork();
 	if (c_pid == -1) {
 		dperror("second vfork");
 		return (-1);
 	}
-	dprintf("second continuing c_pid=%d\n", c_pid);
-
+	dprintf("second continuing c_pid=%d\n", (int)c_pid);
 	if (c_pid == 0) {
 		(void) close(p[0]);
 		(void) close(1);
@@ -377,392 +726,1026 @@
 		(void) close(p[1]);
 		(void) close(2);
 		dprintf("second exec fuser %s\n", file);
-		(void) execle("/usr/sbin/fuser", "fuser", file, NULL, newenv);
+		(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
 		dperror("second exec fuser");
 		_exit(1);
 	}
-
 	(void) close(p[1]);
 	if ((ptr = fdopen(p[0], "r")) != NULL) {
 		while (!feof(ptr)) {
-			if (fscanf(ptr, "%d", &pid) > 0) {
-				(void) sprintf(buf + strlen(PROCFS), "%d", pid);
+			if (fscanf(ptr, "%d", &fuserpid) > 0) {
+				(void) sprintf(buf + strlen(PROCFS), "%d",
+				    fuserpid);
 				if ((fp = open(buf, O_RDONLY)) == -1) {
 					dperror(buf);
 					continue;
 				}
-				if (ioctl(fp, PIOCPSINFO, (char *)&info)
-				    == -1) {
-					dprintf("%d psinfo failed", pid);
+				if (ioctl(fp, PIOCPSINFO,
+				    (char *)&info) == -1) {
+					dprintf("%d psinfo failed", fuserpid);
 					dperror("");
 					(void) close(fp);
 					continue;
 				}
 				(void) close(fp);
 				if (strcmp(info.pr_fname, "vold") == NULL) {
-					dprintf("%d matched vold name\n", pid);
+					dprintf("%d matched vold name\n",
+					    fuserpid);
 					continue;
 				}
 				dprintf("killing %s", info.pr_fname);
-				dprintf("(%d)\n", pid);
-				if ((r = kill(pid, SIGKILL)) == -1) {
-					dprintf("kill %d", pid);
+				dprintf("(%d)\n", fuserpid);
+				if ((r =
+				    kill((pid_t)fuserpid, SIGKILL)) == -1) {
+					dprintf("kill %d", fuserpid);
 					dperror("");
 					break;
 				}
 			}
 		}
-		dprintf("eof reached %x\n", ptr);
 	} else {
-		dperror("fdopen(p[0])");
+		dperror("fdopen(p[0], r)");
 		r = -1;
 	}
+	(void) fclose(ptr);
 
-	(void) fclose(ptr);
 	return (r);
 }
 
-static int
-mk_unalloc(int optflg, char *list)
+int
+mk_unalloc(int optflag, devmap_t *list)
 {
-	char	*file;
 	int	error = 0;
-	int child, status;
-
-	audit_allocate_list(list);
+	int	status;
+	char	**file;
 
-	child = vfork();
-	switch (child) {
-	case -1:
-		return (-1);
-	case 0:
-		(void) setuid(0);
-		file = strtok(list, " ");
-		while (file != NULL) {
-			dprintf("Deallocating %s\n", file);
-			if (mk_revoke(optflg, file) < 0) {
-				dprintf("mk_unalloc: unable to revoke %s\n",
-				    file);
-				dperror("");
-				error = CNTFRC;
-				break;
-			}
-			error = newdac(file, ALLOC_UID, ALLOC_GID,
-			    DEALLOC_MODE);
-			file = strtok(NULL, " ");
+	audit_allocate_list(list->dmap_devlist);
+	file = list->dmap_devarray;
+	if (file == NULL)
+		return (NODMAPERR);
+	for (; *file != NULL; file++) {
+		dprintf("Deallocating %s\n", *file);
+		if (mk_revoke(optflag, *file) < 0) {
+			dprintf("mk_unalloc: unable to revoke %s\n", *file);
+			dperror("");
+			error = CNTFRCERR;
 		}
-		exit(error);
-	default:
-		while (wait(&status) != child);
-		if (WIFEXITED(status)) {
-			return (WEXITSTATUS(status));
-		}
-		return (-1);
+		status = _newdac(*file, ALLOC_UID, ALLOC_GID, DEALLOC_MODE);
+		if (error == 0)
+			error = status;
+
 	}
+
+	return (error);
 }
 
-static int
-exec_clean(int optflg, char *name, char *path)
+int
+mk_error(devmap_t *list)
+{
+	int	status = 0;
+	char	**file;
+
+	audit_allocate_list(list->dmap_devlist);
+	file = list->dmap_devarray;
+	if (file == NULL)
+		return (NODMAPERR);
+	for (; *file != NULL; file++) {
+		dprintf("Putting %s in error state\n", *file);
+		status = _newdac(*file, ALLOC_ERRID, ALLOC_GID, ALLOC_ERR_MODE);
+	}
+
+	return (status);
+}
+
+int
+exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
+    char *clean_arg)
 {
-	char	*mode, *cmd;
-	int	status;
-	int	c;
+	int		c;
+	int		status = 0, exit_status;
+	char		*mode, *cmd, *wdwcmd, *zoneroot;
+	char		*devzone = zonename;
+	char		wdwpath[PATH_MAX];
+	char		zonepath[MAXPATHLEN];
+	char		title[100];
+	char		pw_buf[NSS_BUFLEN_PASSWD];
+	struct passwd	pw_ent;
 
-	if ((optflg & (FORCE_ALL | SILENT)) == (FORCE_ALL | SILENT))
+	zonepath[0] = '\0';
+	if (system_labeled) {
+		if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
+			if (strcmp(clean_arg, ALLOC_CLEAN) == 0) {
+				return (-1);
+			} else if (optflag & FORCE) {
+				(void) strcpy(zonepath, "/");
+				devzone = GLOBAL_ZONENAME;
+			} else {
+				dprintf("unable to get label for %s zone\n",
+				    zonename);
+				return (-1);
+			}
+		} else {
+			(void) strcpy(zonepath, zoneroot);
+			free(zoneroot);
+		}
+	}
+	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
+		return (-1);
+	if (optflag & FORCE_ALL)
 		mode = "-I";
-	else if (optflg & FORCE_ALL)
-		mode = "-i";
-	else if (optflg & FORCE)
+	else if (optflag & FORCE)
 		mode = "-f";
 	else
 		mode = "-s";
+	if (path == NULL)
+		return (0);
 	if ((cmd = strrchr(path, '/')) == NULL)
 		cmd = path;
 	else
 		cmd++;	/* skip leading '/' */
-
 	c = vfork();
 	switch (c) {
 	case -1:
 		return (-1);
 	case 0:
 		(void) setuid(0);
+		if (system_labeled && (optflag & WINDOWING)) {
+			/* First try .windowing version of script */
+			(void) strncpy(wdwpath, path, PATH_MAX);
+			(void) strncat(wdwpath, ".windowing", PATH_MAX);
+			if ((wdwcmd = strrchr(wdwpath, '/')) == NULL)
+				wdwcmd = wdwpath;
+			(void) execl(wdwpath, wdwcmd, mode, devname, clean_arg,
+			    pw_ent.pw_name, devzone, zonepath, NULL);
+			/* If that failed, run regular version via dtterm */
+			(void) snprintf(title, sizeof (title),
+			    "Device %s for %s",
+			    strcmp(clean_arg, ALLOC_CLEAN) == 0 ?
+			    "allocation" : "deallocation", devname);
+			(void) execl("/usr/dt/bin/dtterm", "dtterm",
+			    "-title", title, "-geometry", "x10+100+400",
+			    "-e", "/etc/security/lib/wdwwrapper",
+			    path, mode, devname, clean_arg, pw_ent.pw_name,
+			    devzone, zonepath, NULL);
+			/*
+			 * And if that failed, continue on to try
+			 * running regular version directly.
+			 */
+		}
 		dprintf("clean script: %s, ", path);
 		dprintf("cmd=%s, ", cmd);
 		dprintf("mode=%s, ", mode);
-		dprintf("name=%s\n", name);
-		(void) execle(path, cmd, mode, name, NULL, newenv);
+		if (system_labeled) {
+			dprintf("devname=%s ", devname);
+			dprintf("zonename=%s ", devzone);
+			dprintf("zonepath=%s ", zonepath);
+			dprintf("username=%s\n", pw_ent.pw_name);
+			(void) execl(path, cmd, mode, devname, clean_arg,
+			    pw_ent.pw_name, devzone, zonepath, NULL);
+		} else {
+			dprintf("devname=%s\n", devname);
+			(void) execle(path, cmd, mode, devname, NULL, newenv);
+		}
 		dprintf("Unable to execute clean up script %s\n", path);
 		dperror("");
-		exit(CNTDEXEC);
+		exit(CNTDEXECERR);
 	default:
-		while (wait(&status) != c);
-		if (WIFEXITED(status))
-			return (WEXITSTATUS(status));
-		dprintf("exit status %d\n", status);
+		(void) waitpid(c, &status, 0);
+		dprintf("Child %d", c);
+		if (WIFEXITED(status)) {
+			exit_status = WEXITSTATUS(status);
+			dprintf(" exited, status: %d\n", exit_status);
+			return (exit_status);
+		} else if (WIFSIGNALED(status)) {
+			dprintf(" killed, signal %d\n", WTERMSIG(status));
+		} else {
+			dprintf(": exit status %d\n", status);
+		}
 		return (-1);
 	}
 }
 
-static int
-deallocate_dev(int optflg, devalloc_t *dev_ent, uid_t uid)
+int
+_deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
+    char *zonename)
 {
-	devmap_t *dev_list;
-	char	file_name[MAXPATHLEN];
-	struct stat stat_buf;
-	char	*list;
-	int	error = 0, err;
-	int	bytes_formated;
+	int			bytes = 0;
+	int			error = 0;
+	int			is_authorized = 0;
+	uid_t			nuid;
+	char			*fname = NULL;
+	char			file_name[MAXPATHLEN];
+	char			*devzone = NULL;
+	devmap_t		*dm = NULL, *dm_new = NULL;
+	struct stat		stat_buf;
+	struct state_file	sf;
 
-	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
-	    dev_ent->da_devname);
-	if (bytes_formated <= 0) {
-		return (DEVNAME_ERR);
-	} else if (bytes_formated >= MAXPATHLEN) {
-		dprintf("device name %s is too long.\n", dev_ent->da_devname);
-		return (DEVNAME_TOOLONG);
+	if (dm_in == NULL) {
+		setdmapent();
+		if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
+			enddmapent();
+			dprintf("Unable to find %s in device map database\n",
+			    da->da_devname);
+			return (NODMAPERR);
+		}
+		enddmapent();
+		dm = dm_new;
+	} else {
+		dm = dm_in;
+	}
+	if (system_labeled) {
+		if (_dev_file_name(&sf, dm) != 0) {
+			if (dm_new)
+				freedmapent(dm_new);
+			dprintf("Unable to find %s device files\n",
+			    da->da_devname);
+			error = NODMAPERR;
+			goto out;
+		}
+		fname = sf.sf_path;
+	} else {
+		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
+		    da->da_devname);
+		if (bytes <= 0) {
+			error = DEVNAMEERR;
+			goto out;
+		} else if (bytes >= MAXPATHLEN) {
+			dprintf("device name %s is too long.\n",
+			    da->da_devname);
+			error = DEVLONGERR;
+			goto out;
+		}
+		fname = file_name;
 	}
 
-	audit_allocate_device(file_name);
+	audit_allocate_device(fname);
 
-	if (stat(file_name, &stat_buf)) {
-		dprintf("Unable to stat %s\n", file_name);
-		dperror("Error:");
-		return (DACACC);
+	if (stat(fname, &stat_buf) != 0) {
+		dprintf("Unable to stat %s\n", fname);
+		error = DACACCERR;
+		goto out;
+	}
+	is_authorized = _is_dev_authorized(da, uid);
+	if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
+		dprintf("User %d is unauthorized to deallocate\n", (int)uid);
+		error = UAUTHERR;
+		goto out;
+	}
+	if (system_labeled) {
+		/*
+		 * unless we're here to deallocate by force, check if the
+		 * label at which the device is currently allocated is
+		 * within the user label range.
+		 */
+		if (!(optflag & FORCE) &&
+		    _check_label(da, zonename, uid, CHECK_URANGE) != 0) {
+			error = LABELRNGERR;
+			goto out;
+		}
+	}
+	if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
+	    DEV_ALLOCATED(stat_buf)) {
+		error = ALLOCUERR;
+		goto out;
+	}
+	if (!DEV_ALLOCATED(stat_buf)) {
+		if (DEV_ERRORED(stat_buf)) {
+			if (!(optflag & FORCE)) {
+				error = DEVSTATEERR;
+				goto out;
+			}
+		} else {
+			error = DEVNALLOCERR;
+			goto out;
+		}
 	}
-
-	if (!(optflg & FORCE) && stat_buf.st_uid != uid &&
-	    DEV_ALLOCATED(stat_buf)) {
-		return (NALLOCU);
+	/* All checks passed, time to lock and deallocate */
+	if ((error = lock_dev(fname)) != 0)
+		goto out;
+	if (system_labeled) {
+		devzone = kva_match(da->da_devopts, DAOPT_ZONE);
+		if (devzone && (strcmp(devzone, GLOBAL_ZONENAME) != 0)) {
+			if ((remove_znode(devzone, dm) != 0) &&
+			    !(optflag & FORCE)) {
+				error = ZONEERR;
+				goto out;
+			}
+		}
+	}
+	if ((error = mk_unalloc(optflag, dm)) != 0) {
+		if (!(optflag & FORCE))
+			goto out;
+	}
+	if (system_labeled == 0) {
+		if ((error = _newdac(fname, ALLOC_UID, ALLOC_GID,
+		    DEALLOC_MODE)) != 0) {
+			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
+			    ALLOC_ERR_MODE);
+			goto out;
+		}
+	}
+	/*
+	 * if we are deallocating device owned by someone else,
+	 * pass the owner's uid to the cleaning script.
+	 */
+	nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
+	error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
+	    devzone, DEALLOC_CLEAN);
+	if (error != 0) {
+		if (!(optflag & (FORCE | FORCE_ALL))) {
+			error = CLEANERR;
+			(void) mk_error(dm);
+		} else {
+			error = 0;
+		}
 	}
 
-	if (!(optflg & FORCE_ALL) && !DEV_ALLOCATED(stat_buf)) {
-		if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) {
-			if (!(optflg & FORCE))
-				return (ALLOCERR);
-		} else
-			return (NALLOC);
+out:
+	if (dm_new)
+		freedmapent(dm_new);
+	return (error);
+}
+
+int
+_allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename)
+{
+	int			i;
+	int			bytes = 0;
+	int			error = 0;
+	int			is_authorized = 0;
+	int			dealloc_optflag = 0;
+	char			*fname = NULL;
+	char			file_name[MAXPATHLEN];
+	devmap_t 		*dm;
+	struct stat 		stat_buf;
+	struct state_file	sf;
+	struct zone_path	zpath;
+
+	zpath.count = 0;
+	zpath.path = NULL;
+	setdmapent();
+	if ((dm = getdmapnam(da->da_devname)) == NULL) {
+		enddmapent();
+		dprintf("Unable to find %s in device map database\n",
+		    da->da_devname);
+		return (NODMAPERR);
+	}
+	enddmapent();
+	if (system_labeled) {
+		if (_dev_file_name(&sf, dm) != 0) {
+			freedmapent(dm);
+			dprintf("Unable to find %s device files\n",
+			    da->da_devname);
+			error = NODMAPERR;
+			goto out;
+		}
+		fname = sf.sf_path;
+	} else {
+		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
+		    da->da_devname);
+		if (bytes <= 0) {
+			error = DEVNAMEERR;
+			goto out;
+		} else if (bytes >= MAXPATHLEN) {
+			dprintf("device name %s is too long.\n",
+			    da->da_devname);
+			error = DEVLONGERR;
+			goto out;
+		}
+		fname = file_name;
 	}
 
-	/* All checks passed, time to lock and deallocate */
-	if ((error = lock_dev(file_name)) != 0)
-		return (error);
-
-	if ((err = newdac(file_name, ALLOC_UID, ALLOC_GID, DEALLOC_MODE))
-	    != 0) {
-		(void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE);
-		EXIT(err);
-	}
+	(void) audit_allocate_device(fname);
 
-	if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) {
-		dprintf("Unable to find %s in the device map database\n",
-		    dev_ent->da_devname);
-		EXIT(NODMAPENT);
-	} else {
-		if ((list = strdup(dev_list->dmap_devlist)) == NULL) {
-			EXIT(SYSERROR)
+	if (stat(fname, &stat_buf) != 0) {
+		dprintf("Unable to stat %s\n", fname);
+		dperror("Error:");
+		error = DACACCERR;
+		goto out;
+	}
+	if (DEV_ERRORED(stat_buf)) {
+		error = DEVSTATEERR;
+		goto out;
+	}
+	is_authorized = _is_dev_authorized(da, uid);
+	if (is_authorized == ALLOC_BY_NONE) {
+		dprintf("Device %s is not allocatable\n", da->da_devname);
+		error = UAUTHERR;
+		goto out;
+	} else if (!is_authorized && !(optflag & USERNAME)) {
+		dprintf("User %d is unauthorized to allocate\n", (int)uid);
+		error = UAUTHERR;
+		goto out;
+	}
+	if (system_labeled) {
+		/*
+		 * check if label of the zone to which the device is being
+		 * allocated is within the device label range.
+		 */
+		if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) {
+			error = LABELRNGERR;
+			goto out;
+		}
+	}
+	if (check_devs(dm) == -1) {
+		error = DSPMISSERR;
+		goto out;
+	}
+	if (DEV_ALLOCATED(stat_buf)) {
+		if (optflag & FORCE) {
+			if (optflag & SILENT)
+				dealloc_optflag = FORCE|SILENT;
+			else
+				dealloc_optflag = FORCE;
+			if (_deallocate_dev(dealloc_optflag, da, dm, uid,
+			    zonename)) {
+				dprintf("Couldn't force deallocate device %s\n",
+				    da->da_devname);
+				error = CNTFRCERR;
+				goto out;
+			}
+		} else if (stat_buf.st_uid == uid) {
+			error = PREALLOCERR;
+			goto out;
 		} else {
-			if (mk_unalloc(optflg, list) != 0) {
-				(void) newdac(file_name, ALLOC_UID, ALLOC_GID,
-				    ALLOC_ERR_MODE);
-				free(list);
-				list = NULL;
-				EXIT(DEVLST);
+			error = ALLOCUERR;
+			goto out;
+		}
+	}
+	/* All checks passed, time to lock and allocate */
+	if ((error = lock_dev(fname)) != 0)
+		goto out;
+	if (system_labeled) {
+		/*
+		 * Run the cleaning program; it also mounts allocated
+		 * device if required.
+		 */
+		error = exec_clean(optflag, da->da_devname, da->da_devexec, uid,
+		    zonename, ALLOC_CLEAN);
+		if ((error != 0) && (error != CLEAN_MOUNT)) {
+			error = CLEANERR;
+			(void) mk_error(dm);
+			goto out;
+		}
+		/*
+		 * If not mounted, create zonelinks, if this is not the
+		 * global zone.
+		 */
+		if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) &&
+		    (error != CLEAN_MOUNT)) {
+			if (create_znode(zonename, &zpath, dm) != 0) {
+				error = ZONEERR;
+				goto out;
 			}
 		}
 	}
 
-	if (list != NULL)
-		free(list);
-	if (exec_clean(optflg, dev_ent->da_devname, dev_ent->da_devexec))
-		EXIT(CLEAN_ERR);
+	(void) audit_allocate_list(dm->dmap_devlist);
+
+	if ((error = mk_alloc(dm, uid, &zpath)) != 0) {
+		(void) mk_unalloc(optflag, dm);
+		goto out;
+	}
+
+	if (system_labeled == 0) {
+		if ((error = _newdac(file_name, uid, getgid(),
+		    ALLOC_MODE)) != 0) {
+			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
+			    ALLOC_ERR_MODE);
+			goto out;
+		}
+	}
+	error = 0;
+out:
+	if (zpath.count) {
+		for (i = 0; i < zpath.count; i++)
+			free(zpath.path[i]);
+		free(zpath.path);
+	}
+	freedmapent(dm);
+	return (error);
+}
+
+void
+_store_devnames(int *count, struct devnames *dnms, char *zonename,
+    devalloc_t *da, int flag)
+{
+	int i;
+
+	dnms->dnames = (char **)realloc(dnms->dnames,
+	    (*count + 1) * sizeof (char *));
+	if (da) {
+		dnms->dnames[*count] = strdup(da->da_devname);
+		(*count)++;
+	} else {
+		dnms->dnames[*count] = NULL;
+		if (flag == DA_ADD_ZONE)
+			(void) update_device(dnms->dnames, zonename,
+			    DA_ADD_ZONE);
+		else if (flag == DA_REMOVE_ZONE)
+			(void) update_device(dnms->dnames, NULL,
+			    DA_REMOVE_ZONE);
+		for (i = 0; i < *count; i++)
+			free(dnms->dnames[i]);
+		free(dnms->dnames);
+	}
+}
+
+int
+allocate(int optflag, uid_t uid, char *device, char *zonename)
+{
+	int		count = 0;
+	int		error = 0;
+	devalloc_t	*da;
+	struct devnames	dnms;
+
+	if (optflag & (FORCE | USERID | USERNAME)) {
+		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
+			return (UAUTHERR);
+	}
+	dnms.dnames = NULL;
+	setdaent();
+	if (optflag & TYPE) {
+		/*
+		 * allocate devices of this type
+		 */
+		while ((da = getdatype(device)) != NULL) {
+			if (system_labeled &&
+			    da_check_logindevperm(da->da_devname)) {
+				freedaent(da);
+				continue;
+			}
+			dprintf("trying to allocate %s\n", da->da_devname);
+			error = _allocate_dev(optflag, uid, da, zonename);
+			if (system_labeled && (error == 0)) {
+				/*
+				 * we need to record in device_allocate the
+				 * label (zone name) at which this device is
+				 * being allocated. store this device entry.
+				 */
+				_store_devnames(&count, &dnms, zonename, da, 0);
+			}
+			freedaent(da);
+			error = 0;
+		}
+	} else {
+		/*
+		 * allocate this device
+		 */
+		if ((da = getdanam(device)) == NULL) {
+			enddaent();
+			return (NODAERR);
+		}
+		if (system_labeled && da_check_logindevperm(device)) {
+			freedaent(da);
+			return (LOGINDEVPERMERR);
+		}
+		dprintf("trying to allocate %s\n", da->da_devname);
+		error = _allocate_dev(optflag, uid, da, zonename);
+		/*
+		 * we need to record in device_allocate the label (zone name)
+		 * at which this device is being allocated. store this device
+		 * entry.
+		 */
+		if (system_labeled && (error == 0))
+			_store_devnames(&count, &dnms, zonename, da, 0);
+		freedaent(da);
+	}
+	enddaent();
+	/*
+	 * add to device_allocate labels (zone names) for the devices we
+	 * allocated.
+	 */
+	if (dnms.dnames)
+		_store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE);
+
+	return (error);
+}
+
+/* ARGSUSED */
+int
+deallocate(int optflag, uid_t uid, char *device, char *zonename)
+{
+	int		count = 0;
+	int		error = 0;
+	devalloc_t	*da;
+	struct devnames dnms;
+
+	if (optflag & (FORCE | FORCE_ALL)) {
+		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
+		return (UAUTHERR);
+	}
+	if (optflag & FORCE_ALL)
+		optflag |= FORCE;
+	dnms.dnames = NULL;
+	setdaent();
+	if (optflag & FORCE_ALL) {
+		/*
+		 * deallocate all devices
+		 */
+		while ((da = getdaent()) != NULL) {
+			if (system_labeled &&
+			    da_check_logindevperm(da->da_devname)) {
+				freedaent(da);
+				continue;
+			}
+			dprintf("trying to deallocate %s\n", da->da_devname);
+			error = _deallocate_dev(optflag, da, NULL, uid,
+			    zonename);
+			if (system_labeled && (error == 0)) {
+				/*
+				 * we need to remove this device's allocation
+				 * label (zone name) from device_allocate.
+				 * store this device name.
+				 */
+				_store_devnames(&count, &dnms, zonename, da, 0);
+			}
+			freedaent(da);
+			error = 0;
+		}
+	} else if (system_labeled && optflag & TYPE) {
+		/*
+		 * deallocate all devices of this type
+		 */
+		while ((da = getdatype(device)) != NULL) {
+			if (da_check_logindevperm(da->da_devname)) {
+				freedaent(da);
+				continue;
+			}
+			dprintf("trying to deallocate %s\n", da->da_devname);
+			error = _deallocate_dev(optflag, da, NULL, uid,
+			    zonename);
+			if (error == 0) {
+				/*
+				 * we need to remove this device's allocation
+				 * label (zone name) from device_allocate.
+				 * store this device name.
+				 */
+				_store_devnames(&count, &dnms, zonename, da, 0);
+			}
+			freedaent(da);
+			error = 0;
+		}
+	} else if (!(optflag & TYPE)) {
+		/*
+		 * deallocate this device
+		 */
+		if ((da = getdanam(device)) == NULL) {
+			enddaent();
+			return (NODAERR);
+		}
+		if (system_labeled && da_check_logindevperm(da->da_devname)) {
+			freedaent(da);
+			return (LOGINDEVPERMERR);
+		}
+		dprintf("trying to deallocate %s\n", da->da_devname);
+		error = _deallocate_dev(optflag, da, NULL, uid, zonename);
+		if (system_labeled && (error == 0)) {
+			/*
+			 * we need to remove this device's allocation label
+			 * (zone name) from device_allocate. store this
+			 * device name.
+			 */
+			_store_devnames(&count, &dnms, zonename, da, 0);
+		}
+		freedaent(da);
+	}
+	enddaent();
+	/*
+	 * remove from device_allocate labels (zone names) for the devices we
+	 * deallocated.
+	 */
+	if (dnms.dnames)
+		_store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE);
+
 	return (error);
 }
 
 static int
-allocate_dev(int optflg, uid_t uid, devalloc_t *dev_ent)
+_dev_file_name(struct state_file *sfp, devmap_t *dm)
 {
-	devmap_t *dev_list;
-	char	file_name[MAXPATHLEN];
-	struct stat stat_buf;
-	char	*list;
-	int	error = 0;
-	int	bytes_formated;
-	int	deallocate_optflg = 0;
-
-	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
-	    dev_ent->da_devname);
-	if (bytes_formated <= 0) {
-		return (DEVNAME_ERR);
-	} else if (bytes_formated >= MAXPATHLEN) {
-		dprintf("device name %s is too long.\n", dev_ent->da_devname);
-		return (DEVNAME_TOOLONG);
-	}
-
-	audit_allocate_device(file_name);
-
-	if (stat(file_name, &stat_buf)) {
-		dprintf("Unable to stat %s\n", file_name);
-		dperror("Error:");
-		return (DACACC);
+	sfp->sf_flags = 0;
+	/* if devlist is generated, never leave device in error state */
+	if (dm->dmap_devlist[0] == '`')
+		sfp->sf_flags |= SFF_NO_ERROR;
+	if (dm->dmap_devarray == NULL ||
+	    dm->dmap_devarray[0] == NULL)
+		return (NODMAPERR);
+	(void) strncpy(sfp->sf_path, dm->dmap_devarray[0],
+	    sizeof (sfp->sf_path));
+	sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0';
+	if (sfp->sf_path[0] == '\0') {
+		dprintf("dev_file_name: no device list for %s\n",
+		    dm->dmap_devname);
+		return (NODMAPERR);
 	}
 
-	if (DEV_ALLOCATED(stat_buf)) {
-		if (optflg & FORCE) {
-			if (optflg & SILENT)
-				deallocate_optflg = FORCE|SILENT;
-			else
-				deallocate_optflg = FORCE;
+	return (0);
+}
+
+/*
+ * _check_label -
+ *	checks the device label range against zone label, which is also
+ *	user's current label.
+ *	returns 0 if in range, -1 for all other conditions.
+ *
+ */
+
+static int
+_check_label(devalloc_t *da, char *zonename, uid_t uid, int flag)
+{
+	int		err;
+	int		in_range = 0;
+	char		*alloczone, *lstr;
+	char		pw_buf[NSS_BUFLEN_PASSWD];
+	blrange_t	*range;
+	m_label_t	*zlabel;
+	struct passwd	pw_ent;
+
+	if ((da == NULL) || (zonename == NULL))
+		return (-1);
+
+	if ((zlabel = getzonelabelbyname(zonename)) == NULL) {
+		dprintf("unable to get label for %s zone\n", zonename);
+		return (-1);
+	}
+	if (flag == CHECK_DRANGE) {
+		blrange_t	drange;
 
-			if (deallocate_dev(deallocate_optflg, dev_ent, uid)) {
-				dprintf("Couldn't force deallocate device %s\n",
-				    dev_ent->da_devname);
-				return (CNTFRC);
-			}
-		} else if (stat_buf.st_uid == uid) {
-			return (ALLOC);
-		} else
-			return (ALLOC_OTHER);
-	}
-	if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
-		return (ALLOCERR);
+		drange.lower_bound = blabel_alloc();
+		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
+		if (lstr == NULL) {
+			bsllow(drange.lower_bound);
+		} else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION,
+		    &err) == 0) {
+			dprintf("bad min_label for device %s\n",
+			    da->da_devname);
+			free(zlabel);
+			blabel_free(drange.lower_bound);
+			return (-1);
+		}
+		drange.upper_bound = blabel_alloc();
+		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
+		if (lstr == NULL) {
+			bslhigh(drange.upper_bound);
+		} else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION,
+		    &err) == 0) {
+			dprintf("bad max_label for device %s\n",
+			    da->da_devname);
+			free(zlabel);
+			blabel_free(drange.lower_bound);
+			blabel_free(drange.upper_bound);
+			return (-1);
+		}
+		if (blinrange(zlabel, &drange) == 0) {
+			char	*zlbl = NULL, *min = NULL, *max = NULL;
 
-	if (strcmp(dev_ent->da_devauth, "*") == 0) {
-		dprintf("Device %s is not allocatable\n", dev_ent->da_devname);
-		return (AUTHERR);
-	}
-
-	if (strcmp(dev_ent->da_devauth, "@")) {
-		if (!is_authorized(dev_ent->da_devauth, uid)) {
-			dprintf("User %d is unauthorized to allocate\n",
+			(void) bsltos(zlabel, &zlbl, 0, 0);
+			(void) bsltos(drange.lower_bound, &min, 0, 0);
+			(void) bsltos(drange.upper_bound, &max, 0, 0);
+			dprintf("%s zone label ", zonename);
+			dprintf("%s outside device label range: ", zlbl);
+			dprintf("min - %s, ", min);
+			dprintf("max - %s\n", max);
+			free(zlabel);
+			blabel_free(drange.lower_bound);
+			blabel_free(drange.upper_bound);
+			return (-1);
+		}
+	} else if (flag == CHECK_URANGE) {
+		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
+			dprintf("Unable to get passwd entry for userid %d\n",
+			    (int)uid);
+			free(zlabel);
+			return (-1);
+		}
+		if ((range = getuserrange(pw_ent.pw_name)) == NULL) {
+			dprintf("Unable to get label range for userid %d\n",
 			    (int)uid);
-			return (IMPORT_ERR);
+			free(zlabel);
+			return (-1);
+		}
+		in_range = blinrange(zlabel, range);
+		free(zlabel);
+		blabel_free(range->lower_bound);
+		blabel_free(range->upper_bound);
+		free(range);
+		if (in_range == 0) {
+			dprintf("%s device label ", da->da_devname);
+			dprintf("out of user %d label range\n", (int)uid);
+			return (-1);
+		}
+	} else if (flag == CHECK_ZLABEL) {
+		alloczone = kva_match(da->da_devopts, DAOPT_ZONE);
+		if (alloczone == NULL) {
+			free(zlabel);
+			return (-1);
+		}
+		if (strcmp(zonename, alloczone) != 0) {
+			dprintf("%s zone is different than ", zonename);
+			dprintf("%s zone to which the device ", alloczone);
+			dprintf("%s is allocated\n", da->da_devname);
+			free(zlabel);
+			return (-1);
 		}
 	}
-
-	if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) {
-		dprintf("Unable to find %s in device map database\n",
-		    dev_ent->da_devname);
-		return (NODMAPENT);
-	}
-
-	if ((list = strdup(dev_list->dmap_devlist)) == NULL)
-		return (SYSERROR);
-
-	if (check_devs(list) == -1) {
-		free(list);
-		return (DSPMISS);
-	}
+	free(zlabel);
 
-	/* All checks passed, time to lock and allocate */
-	if ((error = lock_dev(file_name)) != 0) {
-		free(list);
-		return (error);
-	}
-
-	if ((error = newdac(file_name, uid, getgid(), ALLOC_MODE)) != 0) {
-		(void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE);
-		free(list);
-		return (error);
-	}
-
-	/* refresh list from check_devs overwritting it */
-	(void) strcpy(list, dev_list->dmap_devlist);
-	audit_allocate_list(list);
-
-	if (mk_alloc(list, uid) != 0) {
-		/* refresh list from mk_alloc overwritting it */
-		(void) strcpy(list, dev_list->dmap_devlist);
-		(void) mk_unalloc(optflg, list);
-		free(list);
-		return (DEVLST);
-	}
-
-	free(list);
 	return (0);
 }
 
 int
-allocate(int optflg, uid_t uid, char *device)
+create_znode(char *zonename, struct zone_path *zpath, devmap_t *list)
 {
-	devalloc_t	*dev_ent;
-	devmap_t	*dev_list;
+	int		i;
+	int		size;
+	int		len = 0;
+	int		fcount = 0;
+	char		*p, *tmpfile, *zoneroot;
+	char		**file;
+	char		zonepath[MAXPATHLEN];
+	struct stat	statb;
 
-	if (((optflg & FORCE) || uid != getuid()) &&
-	    !is_authorized(DEVICE_REVOKE_AUTH, getuid()))
-		return (NOTAUTH);
+	file = list->dmap_devarray;
+	if (file == NULL)
+		return (NODMAPERR);
+	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
+		dprintf("unable to get label for %s zone\n", zonename);
+		return (1);
+	}
+	(void) strcpy(zonepath, zoneroot);
+	free(zoneroot);
+	if ((p = strstr(zonepath, "/root")) == NULL)
+		return (1);
+	*p = '\0';
+	len = strlen(zonepath);
+	size = sizeof (zonepath);
+	for (; *file != NULL; file++) {
+		if (stat(*file, &statb) == -1) {
+			dprintf("Couldn't stat the file %s\n", *file);
+			return (1);
+		}
+		/*
+		 * First time initialization
+		 */
+		tmpfile = strdup(*file);
+
+		/*
+		 * Most devices have pathnames starting in /dev
+		 * but SunRay devices do not. In SRRS 3.1 they use /tmp.
+		 *
+		 * If the device pathname is not in /dev then create
+		 * a symbolic link to it and put the device in /dev
+		 */
+		if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) {
+			char	*linkdir;
+			char	srclinkdir[MAXPATHLEN];
+			char	dstlinkdir[MAXPATHLEN];
 
-	setdaent();
-	setdmapent();
-
-	if (!(optflg & TYPE)) {
-		if ((dev_ent = getdanam(device)) == NULL) {
-			if ((dev_list = getdmapdev(device)) == NULL)
-				return (NODMAPENT);
-			else if ((dev_ent = getdanam(dev_list->dmap_devname))
-			    == NULL)
-				return (NODAENT);
+			linkdir = strchr(tmpfile + 1, '/');
+			p = strchr(linkdir + 1, '/');
+			*p = '\0';
+			(void) strcpy(dstlinkdir, "/dev");
+			(void) strncat(dstlinkdir, linkdir, MAXPATHLEN);
+			(void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s",
+				zonepath, tmpfile);
+			(void) symlink(dstlinkdir, srclinkdir);
+			*p = '/';
+			(void) strncat(dstlinkdir, p, MAXPATHLEN);
+			free(tmpfile);
+			tmpfile = strdup(dstlinkdir);
+		}
+		if ((p = rindex(tmpfile, '/')) == NULL) {
+			dprintf("bad path in create_znode for %s\n",
+			    tmpfile);
+			return (1);
+		}
+		*p = '\0';
+		(void) strcat(zonepath, tmpfile);
+		*p = '/';
+		if ((mkdirp(zonepath, 0755) != 0) && (errno != EEXIST)) {
+			dprintf("Unable to create directory %s\n", zonepath);
+			return (1);
 		}
-		return (allocate_dev(optflg, uid, dev_ent));
+		zonepath[len] = '\0';
+		if (strlcat(zonepath, tmpfile, size) >= size) {
+			dprintf("Buffer overflow in create_znode for %s\n",
+			    *file);
+			free(tmpfile);
+			return (1);
+		}
+		free(tmpfile);
+		fcount++;
+		if ((zpath->path = (char **)realloc(zpath->path,
+		    (fcount * sizeof (char *)))) == NULL)
+			return (1);
+		zpath->path[zpath->count] = strdup(zonepath);
+		zpath->count = fcount;
+		if (mknod(zonepath, statb.st_mode, statb.st_rdev) == -1) {
+			switch (errno) {
+			case EEXIST:
+				break;
+			default:
+				dprintf("mknod error: %s\n",
+				    strerror(errno));
+				for (i = 0; i <= fcount; i++)
+					free(zpath->path[i]);
+				free(zpath->path);
+				return (1);
+			}
+		}
+		zonepath[len] = '\0';
 	}
 
-	while ((dev_ent = getdatype(device)) != NULL) {
-		dprintf("trying to allocate %s\n", dev_ent->da_devname);
-		if (!allocate_dev(optflg, uid, dev_ent)) {
-			return (0);
-		}
-	}
-	enddaent();
-	return (NO_DEVICE);
+	return (0);
 }
 
 int
-deallocate(int optflg, uid_t uid, char *device)
+remove_znode(char *zonename, devmap_t *dm)
 {
-	DIR	*dev_dir;
-	struct dirent	*dac_file;
-	devalloc_t	*dev_ent;
-	devmap_t	*dev_list;
-	int	error = NODAENT;
+	int		len = 0;
+	char		*zoneroot;
+	char		**file;
+	char		zonepath[MAXPATHLEN];
 
-	if (optflg & (FORCE | FORCE_ALL) &&
-	    !is_authorized(DEVICE_REVOKE_AUTH, getuid()))
-		return (NOTAUTH);
-	if (optflg & FORCE_ALL)
-		optflg |= FORCE;
+	file = dm->dmap_devarray;
+	if (file == NULL)
+		return (NODMAPERR);
+	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
+		(void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename);
+	} else {
+		char *p;
 
-	setdaent();
-	setdmapent();
+		if ((p = strstr(zoneroot, "/root")) == NULL)
+			return (1);
+		*p = '\0';
+		(void)  strcpy(zonepath, zoneroot);
+		free(zoneroot);
+	}
+	/*
+	 * To support SunRay we will just deal with the
+	 * file in /dev, not the symlinks.
+	 */
+	(void) strncat(zonepath, "/dev", MAXPATHLEN);
+	len = strlen(zonepath);
+	for (; *file != NULL; file++) {
+		char *devrelpath;
 
-	if (!(optflg & FORCE_ALL)) {
-		if ((dev_ent = getdanam(device)) == NULL) {
-			if ((dev_list = getdmapdev(device)) == NULL)
-				return (NODMAPENT);
-			else if ((dev_ent = getdanam(dev_list->dmap_devname))
-			    == NULL)
-				return (NODAENT);
+		/*
+		 * remove device node from zone.
+		 *
+		 * SunRay devices don't start with /dev
+		 * so skip over first directory to make
+		 * sure it is /dev. SunRay devices in zones
+		 * will have a symlink into /dev but
+		 * we don't ever delete it.
+		 */
+		devrelpath = strchr(*file + 1, '/');
+
+		if (strlcat(zonepath, devrelpath, MAXPATHLEN) >= MAXPATHLEN) {
+			dprintf("Buffer overflow in remove_znode for %s\n",
+			    *file);
+			return (1);
 		}
-
-		return (deallocate_dev(optflg, dev_ent, uid));
+		errno = 0;
+		if ((unlink(zonepath) == -1) && (errno != ENOENT)) {
+			perror(zonepath);
+			return (1);
+		}
+		zonepath[len] = '\0';
 	}
 
-	if ((dev_dir = opendir(DAC_DIR)) == NULL) {
-		dperror("Can't open DAC_DIR");
-		return (DACACC);
-	}
+	return (0);
+}
+
+int
+update_device(char **devnames, char *zonename, int flag)
+{
+	int		len, rc;
+	char		*optstr = NULL;
+	da_args		dargs;
+	devinfo_t	devinfo;
 
-	while ((dac_file = readdir(dev_dir)) != NULL) {
-		if ((strcmp(dac_file->d_name, ".") == 0) ||
-		    (strcmp(dac_file->d_name, "..") == 0)) {
-			continue;
-		} else {
-			if ((dev_ent = getdanam(dac_file->d_name)) == NULL) {
-				continue;
-			}
-			error = deallocate_dev(optflg, dev_ent, uid);
-		}
+	dargs.optflag = flag;
+	dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY;
+	dargs.rootdir = NULL;
+	dargs.devnames = devnames;
+	devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec =
+	    devinfo.devlist = NULL;
+	if (dargs.optflag & DA_ADD_ZONE) {
+		len = strlen(DAOPT_ZONE) + strlen(zonename) + 3;
+		if ((optstr = (char *)malloc(len)) == NULL)
+			return (-1);
+		(void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN,
+		    zonename);
+		devinfo.devopts = optstr;
 	}
-	(void) closedir(dev_dir);
-	enddaent();
-	return (error);
+	dargs.devinfo = &devinfo;
+
+	rc = da_update_device(&dargs);
+
+	if (optstr)
+		free(optstr);
+
+	return (rc);
 }
--- a/usr/src/cmd/allocate/audio_clean.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/audio_clean.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -53,9 +53,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <stropts.h>
 #include <unistd.h>
-
+#include <bsm/devices.h>
 #include <sys/audioio.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
@@ -67,54 +68,32 @@
 #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
 #endif
 
-#define	BUF_SIZE 512
-#define	DMINFO	"dminfo -v -n"	/* Cmd to xlate name to device */
-#define	AUDIO	"/dev/audio"	/* Device name of audio device */
-
-static char *Audio_dev = AUDIO;
-
 #ifdef	DEBUG
 static void print_info(audio_info_t *);
 static void print_prinfo(audio_prinfo_t *);
 #endif	/* DEBUG */
 
 static void
-usage(char *prog, int verbose)
+usage(char *prog)
 {
-	if (verbose)
-		(void) fprintf(stderr,
-		    gettext("usage: %s [-I|-s|-f|-i] device\n"), prog);
-}
-
-/*
- * Return the first substring in string before the ':' in "item"
- */
-static void
-first_field(char *string, char *item)
-{
-	item = string;
-
-	while (*item != ':')
-		item++;
-	*item = 0;
+	(void) fprintf(stderr, "%s%s", prog,
+	    gettext(" : usage:[-I|-s|-f|-i] device\n"));
 }
 
 int
-main(int argc, char *argv[])
+main(int argc, char **argv)
 {
-	int	err = 0;
+	int		err = 0;
+	int		Audio_fd;
+	int		forced = 0;		/* Command line options */
+	int		initial = 0;
+	int		standard = 0;
+	int		verbose = 1;		/* default is to be verbose */
+	int		c;
+	char		*prog, *devname, *devpath;
+	devmap_t	*dm;
 	struct stat	st;
 	audio_info_t	info;
-	int	i;
-	char	cmd_str[BUF_SIZE];
-	char	map[BUF_SIZE];
-	char	*prog;
-	FILE	*fp;
-	int	Audio_fd;
-	int	forced = 0;		/* Command line options */
-	int	initial = 0;
-	int	standard = 0;
-	int	verbose = 1;		/* default is to be verbose */
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
@@ -126,8 +105,8 @@
 	 * the same thing.
 	 */
 
-	while ((i = getopt(argc, argv, "Iifs")) != EOF) {
-		switch (i) {
+	while ((c = getopt(argc, argv, "Iifs")) != -1) {
+		switch (c) {
 		case 'I':
 			verbose = 0;
 			initial++;
@@ -152,54 +131,49 @@
 		case '?':
 			err++;
 			break;
+		default:
+			err++;
+			break;
 		}
 		if (err) {
-			usage(prog, verbose);
+			if (verbose)
+				usage(prog);
 			exit(1);
 		}
-		argc -= optind;
-		argv += optind;
 	}
 
-	if (argv[0] == NULL) {	/* no device name */
-		usage(prog, verbose);
+	if ((argc - optind) != 1) {
+		if (verbose)
+			usage(prog);
 		exit(1);
-	}
-
-	if (strlen(argv[0]) > (BUF_SIZE - sizeof (DMINFO) - 2)) {
-		(void) fprintf(stderr, gettext("device name %s too long\n"),
-		    argv[0]);
-		exit(1);
+	} else {
+		devname = argv[optind];
 	}
 
-	(void) strcpy(cmd_str, DMINFO);
-	(void) strcat(cmd_str, " ");
-	(void) strcat(cmd_str, argv[0]);	/* device name */
-
-	if ((fp = popen(cmd_str, "r")) == NULL) {
+	setdmapent();
+	if ((dm = getdmapnam(devname)) == NULL) {
+		enddmapent();
 		if (verbose)
-			(void) fprintf(stderr,
-			    gettext("%s couldn't execute \"%s\"\n"), prog,
-			    cmd_str);
-		exit(1);
+			(void) fprintf(stderr, "%s%s",
+			    devname,
+			    gettext(" : No such allocatable device\n"));
+			exit(1);
 	}
-
-	if (fread(map, 1, BUF_SIZE, fp) == 0) {
+	enddmapent();
+	if (dm->dmap_devarray == NULL || dm->dmap_devarray[0] == NULL) {
 		if (verbose)
-			(void) fprintf(stderr,
-			    gettext("%s no results from \"%s\"\n"), prog,
-			    cmd_str);
-		exit(1);
+			(void) fprintf(stderr, "%s%s",
+			    devname,
+			    gettext(" : No such allocatable device\n"));
+			exit(1);
 	}
-
-	(void) pclose(fp);
-
-	first_field(map, Audio_dev);  /* Put the 1st field in dev */
+	devpath = strdup(dm->dmap_devarray[0]);
+	freedmapent(dm);
 
 	/*
 	 * Validate and open the audio device
 	 */
-	err = stat(Audio_dev, &st);
+	err = stat(devpath, &st);
 
 	if (err < 0) {
 		if (verbose) {
@@ -213,7 +187,7 @@
 		if (verbose)
 			(void) fprintf(stderr,
 			    gettext("%s: %s is not an audio device\n"), prog,
-			    Audio_dev);
+			    devpath);
 		exit(1);
 	}
 
@@ -222,26 +196,18 @@
 	 * using it we check to see if we're going to hang before we
 	 * do anything.
 	 */
-	/* Try it quickly, first */
-	Audio_fd = open(Audio_dev, O_WRONLY | O_NDELAY);
+	Audio_fd = open(devpath, O_WRONLY | O_NDELAY);
 
 	if ((Audio_fd < 0) && (errno == EBUSY)) {
 		if (verbose)
 			(void) fprintf(stderr, gettext("%s: waiting for %s..."),
-			    prog, Audio_dev);
-
-		/* Now hang until it's open */
-		Audio_fd = open(Audio_dev, O_WRONLY);
-		if (Audio_fd < 0) {
-			if (verbose)
-				perror(Audio_dev);
-			exit(1);
-		}
+			    prog, devpath);
+		exit(0);
 	} else if (Audio_fd < 0) {
 		if (verbose) {
 			(void) fprintf(stderr, gettext("%s: error opening "),
 			    prog);
-			perror(Audio_dev);
+			perror(devpath);
 		}
 		exit(1);
 	}
@@ -253,6 +219,7 @@
 
 	if (ioctl(Audio_fd, AUDIO_GETINFO, &info) != 0)  {
 		perror("Ioctl AUDIO_GETINFO error");
+		(void) close(Audio_fd);
 		exit(1);
 	}
 
@@ -265,12 +232,14 @@
 	if (ioctl(Audio_fd, AUDIO_SETINFO, &info) != 0) {
 		if (verbose)
 			perror(gettext("Ioctl AUDIO_SETINFO error"));
+		(void) close(Audio_fd);
 		exit(1);
 	}
 
 #ifdef	DEBUG
 	if (ioctl(Audio_fd, AUDIO_GETINFO, &info) != 0)  {
 		perror("Ioctl AUDIO_GETINFO-2 error");
+		(void) close(Audio_fd);
 		exit(1);
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/allocate/dminfo.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,486 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <bsm/devices.h>
+#define	DMPFILE	"/etc/security/device_maps"
+#define	RETRY_SLEEP	6
+#define	RETRY_COUNT	10
+#define	EINVOKE	2
+#define	EFAIL 1
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN "SUNW_BSM_DMINFO"
+#endif
+
+extern off_t lseek();
+
+char	*getdmapfield();
+char	*getdmapdfield();
+static void	printdmapent();
+static void	dmapi_err();
+
+static char	*prog_name;
+
+/*
+ * printdmapent(dmapp) prints a devmap_t structure pointed to by dmapp.
+ */
+static void
+printdmapent(dmapp)
+	devmap_t *dmapp;
+{
+	(void) printf("%s:", dmapp->dmap_devname);
+	(void) printf("%s:", dmapp->dmap_devtype);
+	(void) printf("%s", dmapp->dmap_devlist);
+	(void) printf("\n");
+}
+
+
+/*
+ * dmapi_err(exit_code,err_msg) prints message pointed to by err_msg to
+ * stderr. Then prints usage message to stderr. Then exits program with
+ * exit_code.
+ *
+ */
+static void
+dmapi_err(int exit_code, char *err_msg)
+{
+	if (err_msg != NULL) {
+		(void) fprintf(stderr, "dmapinfo:%s\n", err_msg);
+	}
+	if (exit_code == EINVOKE) {
+		(void) fprintf(stderr,
+			"Usage: %s [-v] [-a] [-f filename] %s\n",
+			prog_name,
+			"[-d device ...]");
+		(void) fprintf(stderr,
+			"       %s [-v] [-a] [-f filename] %s\n",
+			prog_name,
+			"[-n name ...]");
+		(void) fprintf(stderr,
+			"       %s [-v] [-a] [-f filename] %s\n",
+			prog_name,
+			"[-t type ...]");
+		(void) fprintf(stderr,
+			"       %s [-v] [-a] [-f filename] %s\n",
+			prog_name,
+			"[-u Entry]");
+	}
+
+	exit(exit_code);
+}
+
+int
+main(int argc, char **argv)
+{
+	devmap_t *dmapp;
+	devmap_t dmap;
+	char	*mptr;
+	char	*tptr;
+	char	*nptr;
+	char	*filename = DMPFILE;
+	int	name = 0;
+	int	device = 0;
+	int	file = 0;
+	int	verbose = 0;
+	int	cntr = 0;
+	int	any = 0;
+	int	update = 0;
+	int	tp = 0;
+	int	des;
+	int	status;
+
+	/* Internationalization */
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+
+	/*
+	 * point prog_name to invocation name
+	 */
+	if ((tptr = strrchr(*argv, '/')) != NULL)
+		prog_name = ++tptr;
+		else
+		prog_name = *argv;
+	argc--;
+	argv++;
+	/*
+	 * parse arguments
+	 */
+	while ((argc >= 1) && (argv[0][0] == '-')) {
+		switch (argv[0][1]) {
+		case 'a':
+			any++;
+			break;
+		case 'd':
+			if ((name) || (device) || (update) || (tp)) {
+				dmapi_err(EINVOKE,
+					gettext("option conflict"));
+			}
+			device++;
+			break;
+		case 'f':
+			argc--;
+			argv++;
+			if (argc <= 0)
+				dmapi_err(EINVOKE,
+					gettext("missing file name"));
+			filename = *argv;
+			file++;
+			break;
+		case 'n':
+			if ((name) || (device) || (update) || (tp)) {
+				dmapi_err(EINVOKE,
+					gettext("option conflict"));
+			}
+			name++;
+			break;
+		case 't':
+			if ((name) || (device) || (update) || (tp)) {
+				dmapi_err(EINVOKE,
+					gettext("option conflict"));
+			}
+			tp++;
+			break;
+		case 'u':
+			if ((name) || (device) || (update) || (tp)) {
+				dmapi_err(EINVOKE,
+					gettext("option conflict"));
+			}
+			update++;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		default:
+			dmapi_err(EINVOKE,
+				gettext("bad option"));
+			break;
+		}
+		argc--;
+		argv++;
+	}
+	/*
+	 * -d(device) -n(name) and -u(update) switches require at least one
+	 * argument.
+	 */
+	if (file)
+		setdmapfile(filename);
+	if ((device) || (name) || (update) || (tp)) {
+		if (argc < 1) {
+			dmapi_err(EINVOKE,
+				gettext("insufficient args for this option"));
+		}
+	}
+	if (update) {
+		/*
+		 * -u(update) switch requires only one argument
+		 */
+		if (argc != 1) {
+			dmapi_err(EINVOKE,
+				gettext("too many args for this option"));
+		}
+		/*
+		 * read entry argument from stdin into a devmap_t known as dmap
+		 */
+		if ((dmap.dmap_devname = getdmapfield(*argv)) == NULL) {
+			dmapi_err(EINVOKE,
+				gettext("Bad dmap_devname in entry argument"));
+		}
+		if ((dmap.dmap_devtype = getdmapfield(NULL)) ==
+			NULL) {
+			dmapi_err(EINVOKE,
+				gettext("Bad dmap_devtype in entry Argument"));
+		}
+		if ((dmap.dmap_devlist = getdmapfield(NULL)) ==
+			NULL) {
+			dmapi_err(EINVOKE,
+				gettext("Bad dmap_devlist in entry argument"));
+		}
+		/*
+		 * Find out how long device list is and create a buffer to
+		 * hold it.  Then copy it there. This is done since we do not
+		 * want to corrupt the existing string.
+		 */
+		cntr = strlen(dmap.dmap_devlist) + 1;
+		mptr = calloc((unsigned)cntr, sizeof (char));
+		if (mptr == NULL) {
+			if (verbose) {
+				(void) fprintf(stderr,
+					gettext(
+					"dmapinfo: Cannot calloc memory\n"));
+			}
+			exit(1);
+		}
+		(void) strcpy(mptr, dmap.dmap_devlist);
+		/*
+		 * open the device maps file for read/ write. We are not
+		 * sure we want to write to it yet but we may and this is a
+		 * easy way to get the file descriptor. We want the file
+		 * descriptor so we can lock the file.
+		 */
+		if ((des = open(filename, O_RDWR)) < 0) {
+			if (verbose) {
+				(void) fprintf(stderr,
+				gettext("dmapinfo: Cannot open %s\n"),
+				    filename);
+			}
+			exit(1);
+		}
+		cntr = 0;
+#ifdef CMW
+		while ((status = flock(des, LOCK_EX | LOCK_NB) == -1) &&
+			(cntr++ < RETRY_COUNT)) {
+			(void) sleep(RETRY_SLEEP);
+		}
+#else
+		while (((status = lockf(des, F_TLOCK, 0)) == -1) &&
+			(cntr++ < RETRY_COUNT)) {
+			(void) sleep(RETRY_SLEEP);
+		}
+#endif
+		if (status == -1) {
+			if (verbose) {
+				(void) fprintf(stderr,
+			gettext("dmapinfo: Cannot lock %s\n"), filename);
+			}
+			exit(1);
+		}
+		/*
+		 * Now that we have the device_maps file then lets check
+		 * for previous entrys with the same name.  If it already
+		 * exists then we will exit with status of 1.
+		 */
+		if (verbose) {
+			(void) fprintf(stderr,
+			gettext("dmapinfo: Checking %s for name (%s).\n"),
+				filename, dmap.dmap_devname);
+		}
+		if (getdmapnam(dmap.dmap_devname) != NULL) {
+			if (verbose) {
+				(void) fprintf(stderr,
+			gettext("dmapinfo: Device name (%s) found in %s.\n"),
+					dmap.dmap_devname, filename);
+			}
+			exit(1);
+		}
+		if (verbose) {
+			(void) fprintf(stderr,
+		gettext("dmapinfo: Device name (%s) not found in %s.\n"),
+				dmap.dmap_devname, filename);
+		}
+		/*
+		 * We now Know name does not exist and now we need to check
+		 * to see if any of the devices in the device list are in the
+		 * device maps file. If the already exist then we will exit
+		 * with a status of 1.
+		 */
+		nptr = mptr;
+		nptr = getdmapdfield(nptr);
+		while (nptr) {
+			if (verbose) {
+				(void) fprintf(stderr,
+				    gettext("dmapinfo: "
+					"Check %s for device (%s).\n"),
+				    filename, nptr);
+			}
+			if (getdmapdev(nptr) != NULL) {
+				if (verbose) {
+					(void) fprintf(stderr,
+					    gettext("dmapinfo: "
+						"Device (%s) found in %s.\n"),
+					    nptr, filename);
+				}
+				exit(1);
+			}
+			if (verbose) {
+				(void) fprintf(stderr,
+				    gettext("dmapinfo: "
+					"Device (%s) not found in %s.\n"),
+				    nptr, filename);
+			}
+			nptr = getdmapdfield(NULL);
+		}
+		/*
+		 * Good the entry is uniq. So lets find out how long it is
+		 * and add it to the end of device maps file in a pretty
+		 * way.
+		 */
+		if (verbose) {
+			(void) fprintf(stderr, "dmapinfo: Adding entry to %s\n",
+				filename);
+			printdmapent(&dmap);
+		}
+		cntr = strlen(dmap.dmap_devname);
+		cntr += strlen(dmap.dmap_devtype);
+		cntr += strlen(dmap.dmap_devlist);
+		cntr += 15;
+		tptr = calloc((unsigned)cntr, sizeof (char));
+		if (tptr == NULL) {
+			exit(1);
+		}
+		(void) strcat(tptr, dmap.dmap_devname);
+		(void) strcat(tptr, ":\\\n\t");
+		(void) strcat(tptr, dmap.dmap_devtype);
+		(void) strcat(tptr, ":\\\n\t");
+		(void) strcat(tptr, dmap.dmap_devlist);
+		(void) strcat(tptr, ":\\\n\t");
+		(void) strcat(tptr, "\n");
+		cntr = strlen(tptr);
+#ifdef CMW
+		if (lseek(des, 0L, L_XTND) == -1L) {
+			exit(1);
+		}
+#else
+		if (lseek(des, 0L, SEEK_END) == -1L) {
+			exit(1);
+		}
+#endif
+		if (write(des, tptr, cntr) == -1) {
+			exit(1);
+		}
+		if (close(des) == -1) {
+			exit(1);
+		}
+		if (verbose) {
+			(void) fprintf(stderr, "dmapinfo: Entry added to %s\n",
+				filename);
+		}
+		exit(0);
+	}
+	/*
+	 * Look for devices in device_maps file. If verbose switch is set
+	 * then print entry(s) found. If "any" switch  is set then, if any
+	 * device is found will result in a exit status of 0. If "any" switch
+	 * is not set then, if any device is not will result in a exit status
+	 * of 1.
+	 */
+	if (device) {
+		setdmapent();
+		while (argc >= 1) {
+			if ((dmapp = getdmapdev(*argv)) != NULL) {
+				if (verbose) {
+					printdmapent(dmapp);
+				}
+				cntr++;
+			} else if (any == 0) {
+				enddmapent();
+				exit(1);
+			}
+			argc--;
+			argv++;
+		}
+		enddmapent();
+		if (cntr != 0)
+			exit(0);
+		exit(1);
+	}
+	/*
+	 * Look for names in device_maps file. If verbose switch is set
+	 * then print entry(s) found. If "any" switch  is set then, if any
+	 * name is found will result in a exit status of 0. If "any" switch
+	 * is not set then, if any name is not will result in a exit status
+	 * of 1.
+	 */
+	if (name) {
+		setdmapent();
+		while (argc >= 1) {
+			if ((dmapp = getdmapnam(*argv)) != NULL) {
+				if (verbose) {
+					printdmapent(dmapp);
+				}
+				cntr++;
+			} else if (any == 0)
+				exit(1);
+			argc--;
+			argv++;
+		}
+		enddmapent();
+		if (cntr != 0)
+			exit(0);
+		exit(1);
+	}
+	/*
+	 * Read all entrys from device maps file. If verbose flag is set
+	 * then all the device maps files are printed.  This is useful for
+	 * piping to grep. Also this option used without the verbose option
+	 * is useful to check for device maps file and for at least one
+	 * entry.  If the device maps file is found and there is one entry
+	 * the return status is 0.
+	 */
+	if (tp) {
+		cntr = 0;
+		setdmapent();
+		while (argc >= 1) {
+			while ((dmapp = getdmaptype(*argv)) != 0) {
+				cntr++;
+				if (verbose) {
+					printdmapent(dmapp);
+				}
+			}
+			if ((any == 0) && (cntr == 0)) {
+				enddmapent();
+				exit(1);
+			}
+			argc--;
+			argv++;
+		}
+		enddmapent();
+		if (cntr == 0)
+			exit(1);
+		exit(0);
+	}
+	/*
+	 * Read all entrys from device maps file. If verbose flag is set
+	 * then all the device maps files are printed.  This is useful for
+	 * piping to grep. Also this option used without the verbose option
+	 * is useful to check for device maps file and for atleast one
+	 * entry.  If the device maps file is found and there is one entry
+	 * the return status is 0.
+	 */
+	cntr = 0;
+	setdmapent();
+	while ((dmapp = getdmapent()) != 0) {
+		cntr++;
+		if (verbose) {
+			printdmapent(dmapp);
+		}
+	}
+	enddmapent();
+	if (cntr == 0)
+		exit(1);
+	return (0);
+}
--- a/usr/src/cmd/allocate/mkdevalloc.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/allocate/mkdevalloc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -49,27 +49,40 @@
  *		/dev/nsr*
  *		/dev/dsk/c?t?d0s?
  *		/dev/rdsk/c?t?d0s?
+ *
  */
 
+#include <errno.h>
+#include <fcntl.h>
 #include <sys/types.h>	/* for stat(2), etc. */
 #include <sys/stat.h>
 #include <dirent.h>	/* for readdir(3), etc. */
 #include <unistd.h>	/* for readlink(2) */
+#include <stropts.h>
 #include <string.h>	/* for strcpy(3), etc. */
 #include <strings.h>	/* for bcopy(3C), etc. */
 #include <stdio.h>	/* for perror(3) */
 #include <stdlib.h>	/* for atoi(3) */
+#include <sys/dkio.h>
 #include <locale.h>
 #include <libintl.h>
+#include <libdevinfo.h>
+#include <secdb.h>
 #include <auth_attr.h>
 #include <auth_list.h>
-#include "allocate.h"   /* for SECLIB */
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
+#include <tsol/label.h>
 
 #ifndef TEXT_DOMAIN
 #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
 #endif
 
+#define	MKDEVALLOC	"mkdevalloc"
+#define	MKDEVMAPS	"mkdevmaps"
+
 #define	DELTA	5	/* array size delta when full */
+#define	SECLIB	"/etc/security/lib"
 
 /* "/dev/rst...", "/dev/nrst...", "/dev/rmt/..." */
 struct tape {
@@ -82,6 +95,7 @@
 #define	SIZE_OF_NRST 4		/* |nrmt| */
 #define	SIZE_OF_TMP  4		/* |/tmp| */
 #define	SIZE_OF_RMT  8		/* |/dev/rmt| */
+#define	TAPE_CLEAN    SECLIB"/st_clean"
 
 /* "/dev/audio", "/dev/audioctl", "/dev/sound/..." */
 struct audio {
@@ -91,6 +105,7 @@
 } *audio;
 #define	DFLT_NAUDIO   10	/* size of initial array */
 #define	SIZE_OF_SOUND 10	/* |/dev/sound| */
+#define	AUDIO_CLEAN   SECLIB"/audio_clean"
 
 /* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */
 struct cd {
@@ -105,7 +120,17 @@
 #define	SIZE_OF_RSR  3		/* |rsr| */
 #define	SIZE_OF_DSK  8		/* |/dev/dsk| */
 #define	SIZE_OF_RDSK 9		/* |/dev/rdsk| */
+#define	CD_CLEAN    SECLIB"/sr_clean"
 
+/* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */
+struct rmdisk {
+	char	*name;
+	char	*device;
+	int	id;
+	int	controller;
+	int	number;
+} *rmdisk, *rmdisk_r;
+#define	DFLT_RMDISK	10	/* size of initial array */
 
 /* "/dev/fd0*", "/dev/rfd0*", "/dev/fd1*", "/dev/rfd1*" */
 struct fp {
@@ -116,30 +141,72 @@
 #define	DFLT_NFP    10		/* size of initial array */
 #define	SIZE_OF_FD0  3		/* |fd0| */
 #define	SIZE_OF_RFD0 4		/* |rfd0| */
+#define	FLOPPY_CLEAN SECLIB"/fd_clean"
 
 static void dotape();
 static void doaudio();
 static void dofloppy();
-static void docd();
+static int docd();
+static void dormdisk(int);
 static void initmem();
 static int  expandmem(int, void **, int);
 static void no_memory(void);
 
+int		system_labeled = 0;
+int		do_devalloc = 0;
+int		do_devmaps = 0;
+int		do_files = 0;
+devlist_t	devlist;
+
 int
-main(void)
+main(int argc, char **argv)
 {
+	int		cd_count = 0;
+	char		*progname;
+	struct stat	tx_stat;
+
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
-	initmem();		/* initialize memory */
-
-	dotape();		/* do tape */
+	if ((progname = strrchr(argv[0], '/')) == NULL)
+		progname = argv[0];
+	else
+		progname++;
+	if (strcmp(progname, MKDEVALLOC) == 0)
+		do_devalloc = 1;
+	else if (strcmp(progname, MKDEVMAPS) == 0)
+		do_devmaps = 1;
+	else
+		exit(1);
 
-	doaudio();		/* do audio */
+	system_labeled = is_system_labeled();
+	if (system_labeled == 0) {
+		/*
+		 * is_system_labeled() will return false in case we are
+		 * starting before the first reboot after Trusted Extensions
+		 * is installed. we check for a well known TX binary to
+		 * to see if TX is installed.
+		 */
+		if (stat(DA_LABEL_CHECK, &tx_stat) == 0)
+			system_labeled = 1;
+	}
 
-	dofloppy();		/* do floppy */
+	if (system_labeled && do_devalloc && (argc == 2) &&
+	    (strcmp(argv[1], DA_IS_LABELED) == 0)) {
+		/*
+		 * write device entries to device_allocate and device_maps.
+		 * default is to print them on stdout.
+		 */
+		do_files = 1;
+	}
 
-	docd();			/* do cd */
+	initmem();		/* initialize memory */
+	dotape();
+	doaudio();
+	dofloppy();
+	cd_count = docd();
+	if (system_labeled)
+		dormdisk(cd_count);
 
 	return (0);
 }
@@ -149,13 +216,18 @@
 {
 	DIR *dirp;
 	struct dirent *dep;	/* directory entry pointer */
-	int	i, j, n;
+	int	i, j;
 	char	*nm;		/* name/device of special device */
 	char	linkvalue[2048];	/* symlink value */
 	struct stat stat;	/* determine if it's a symlink */
 	int	sz;		/* size of symlink value */
 	char	*cp;		/* pointer into string */
 	int	ntape;		/* max array size */
+	int	tape_count;
+	int	first = 0;
+	char	*dname, *dtype, *dclean;
+	da_args	dargs;
+	deventry_t *entry;
 
 	ntape = DFLT_NTAPE;
 
@@ -260,30 +332,92 @@
 
 		i++;
 	}
-	n = i;
+	tape_count = i;
 
 	(void) closedir(dirp);
 
 	/* remove duplicate entries */
-	for (i = 0; i < n - 1; i++) {
-		for (j = i + 1; j < n; j++) {
+	for (i = 0; i < tape_count - 1; i++) {
+		for (j = i + 1; j < tape_count; j++) {
 			if (strcmp(tape[i].device, tape[j].device))
 				continue;
 			tape[j].number = -1;
 		}
 	}
 
-	/* print out device_allocate entries for tape devices */
+	if (system_labeled) {
+		dname = DA_TAPE_NAME;
+		dtype = DA_TAPE_TYPE;
+		dclean = DA_DEFAULT_TAPE_CLEAN;
+	} else {
+		dname = "st";
+		dtype = "st";
+		dclean = TAPE_CLEAN;
+	}
 	for (i = 0; i < 8; i++) {
-		for (j = 0; j < n; j++) {
-			if (tape[j].number == i) {
-				(void) printf(
-					"st%d;st;reserved;reserved;%s;",
-					i, DEFAULT_DEV_ALLOC_AUTH);
-				(void) printf("%s%s\n", SECLIB, "/st_clean");
+		for (j = 0; j < tape_count; j++) {
+			if (tape[j].number != i)
+				continue;
+			if (do_files) {
+				(void) da_add_list(&devlist, tape[j].name, i,
+				    DA_TAPE);
+			} else if (do_devalloc) {
+				/* print device_allocate for tape devices */
+				if (system_labeled) {
+					(void) printf("%s%d%s\\\n",
+					    dname, i, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_TAPE_TYPE, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DEFAULT_DEV_ALLOC_AUTH,
+					    KV_DELIMITER);
+					(void) printf("\t%s\n\n", dclean);
+				} else {
+					(void) printf(
+					    "st%d;st;reserved;reserved;%s;",
+					    i, DEFAULT_DEV_ALLOC_AUTH);
+					(void) printf("%s%s\n", SECLIB,
+					    "/st_clean");
+				}
 				break;
+			} else if (do_devmaps) {
+				/* print device_maps for tape devices */
+				if (first) {
+					(void) printf(" ");
+				} else {
+					if (system_labeled) {
+						(void) printf("%s%d%s\\\n",
+						    dname, i, KV_TOKEN_DELIMIT);
+						(void) printf("\t%s%s\\\n",
+						    dtype, KV_TOKEN_DELIMIT);
+						(void) printf("\t");
+					} else {
+						(void) printf("st%d:\\\n", i);
+						(void) printf("\trmt:\\\n");
+						(void) printf("\t");
+					}
+						first++;
+				}
+				(void) printf("%s", tape[j].name);
 			}
 		}
+		if (do_devmaps && first) {
+			(void) printf("\n\n");
+			first = 0;
+		}
+	}
+	if (do_files && tape_count) {
+		dargs.rootdir = NULL;
+		dargs.devnames = NULL;
+		dargs.optflag = DA_ADD;
+		for (entry = devlist.tape; entry != NULL; entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
+		}
 	}
 }
 
@@ -292,13 +426,20 @@
 {
 	DIR *dirp;
 	struct dirent *dep;	/* directory entry pointer */
-	int	i, j, n;
+	int	i, j;
 	char	*nm;		/* name/device of special device */
 	char	linkvalue[2048];	/* symlink value */
 	struct stat stat;	/* determine if it's a symlink */
 	int	sz;		/* size of symlink value */
 	char	*cp;		/* pointer into string */
 	int	naudio;		/* max array size */
+	int	audio_count = 0;
+	int	len, slen;
+	int	first = 0;
+	char	dname[128];
+	char	*dclean;
+	da_args	dargs;
+	deventry_t *entry;
 
 	naudio = DFLT_NAUDIO;
 
@@ -397,28 +538,90 @@
 	(void) closedir(dirp);
 
 skip:
-	n = i;
+	audio_count = i;
 
 	/* remove duplicate entries */
-	for (i = 0; i < n - 1; i++) {
-		for (j = i + 1; j < n; j++) {
+	for (i = 0; i < audio_count - 1; i++) {
+		for (j = i + 1; j < audio_count; j++) {
 			if (strcmp(audio[i].device, audio[j].device))
 				continue;
 			audio[j].number = -1;
 		}
 	}
 
-	/* print out device_allocate entries for tape devices */
+	/* print out device_allocate entries for audio devices */
+	(void) strcpy(dname, DA_AUDIO_NAME);
+	slen = strlen(DA_AUDIO_NAME);
+	len = sizeof (dname) - slen;
+	dclean = system_labeled ? DA_DEFAULT_AUDIO_CLEAN : AUDIO_CLEAN;
 	for (i = 0; i < 8; i++) {
-		for (j = 0; j < n; j++) {
-			if (audio[j].number == i) {
-				(void) printf("audio;audio;");
-				(void) printf("reserved;reserved;%s;",
-				    DEFAULT_DEV_ALLOC_AUTH);
-				(void) printf("%s%s\n", SECLIB, "/audio_clean");
+		for (j = 0; j < audio_count; j++) {
+			if (audio[j].number != i)
+				continue;
+			if (system_labeled)
+				(void) snprintf(dname+slen, len, "%d", i);
+			if (do_files) {
+				(void) da_add_list(&devlist, audio[j].name,
+				    i, DA_AUDIO);
+			} else if (do_devalloc) {
+				/* print device_allocate for audio devices */
+				if (system_labeled) {
+					(void) printf("%s%s\\\n",
+					    dname, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_AUDIO_TYPE, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DEFAULT_DEV_ALLOC_AUTH,
+					    KV_DELIMITER);
+					(void) printf("\t%s\n\n", dclean);
+				} else {
+					(void) printf("audio;audio;");
+					(void) printf("reserved;reserved;%s;",
+					    DEFAULT_DEV_ALLOC_AUTH);
+					(void) printf("%s%s\n", SECLIB,
+					    "/audio_clean");
+				}
 				break;
+			} else if (do_devmaps) {
+				/* print device_maps for audio devices */
+				if (first) {
+					(void) printf(" ");
+				} else {
+					if (system_labeled) {
+						(void) printf("%s%s\\\n",
+						    dname, KV_TOKEN_DELIMIT);
+						(void) printf("\t%s%s\\\n",
+						    DA_AUDIO_TYPE,
+						    KV_TOKEN_DELIMIT);
+						(void) printf("\t");
+					} else {
+						(void) printf("audio:\\\n");
+						(void) printf("\taudio:\\\n");
+						(void) printf("\t");
+					}
+					first++;
+				}
+				(void) printf("%s", audio[j].name);
 			}
 		}
+		if (do_devmaps && first) {
+			(void) printf("\n\n");
+			first = 0;
+		}
+	}
+	if (do_files && audio_count) {
+		dargs.rootdir = NULL;
+		dargs.devnames = NULL;
+		dargs.optflag = DA_ADD;
+		for (entry = devlist.audio; entry != NULL;
+		    entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
+		}
 	}
 }
 
@@ -427,13 +630,18 @@
 {
 	DIR *dirp;
 	struct dirent *dep;	/* directory entry pointer */
-	int i, j, n;
+	int i, j;
 	char *nm;		/* name/device of special device */
 	char linkvalue[2048];	/* symlink value */
 	struct stat stat;	/* determine if it's a symlink */
 	int sz;			/* size of symlink value */
 	char *cp;		/* pointer into string */
 	int nfp;		/* max array size */
+	int floppy_count = 0;
+	int first = 0;
+	char *dname, *dclean;
+	da_args dargs;
+	deventry_t *entry;
 
 	nfp = DFLT_NFP;
 
@@ -500,27 +708,96 @@
 
 	(void) closedir(dirp);
 
-	n = i;
+	floppy_count = i;
 
-	/* print out device_allocate entries for tape devices */
+	/* print out device_allocate entries for floppy devices */
+	if (system_labeled) {
+		dname = DA_FLOPPY_NAME;
+		dclean = DA_DEFAULT_DISK_CLEAN;
+	} else {
+		dname = "fd";
+		dclean = FLOPPY_CLEAN;
+	}
 	for (i = 0; i < 8; i++) {
-	    for (j = 0; j < n; j++) {
-		if (fp[j].number == i) {
-		    (void) printf("fd%d;fd;reserved;reserved;%s;",
-			i, DEFAULT_DEV_ALLOC_AUTH);
-		    (void) printf("/etc/security/lib/fd_clean\n");
-		    break;
+		for (j = 0; j < floppy_count; j++) {
+			if (fp[j].number != i)
+				continue;
+			if (do_files) {
+				(void) da_add_list(&devlist, fp[j].name, i,
+				    DA_FLOPPY);
+			} else if (do_devalloc) {
+				/* print device_allocate for floppy devices */
+				if (system_labeled) {
+					(void) printf("%s%d%s\\\n",
+					    dname, i, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_FLOPPY_TYPE, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DEFAULT_DEV_ALLOC_AUTH,
+					    KV_DELIMITER);
+					(void) printf("\t%s\n\n", dclean);
+				} else {
+					(void) printf(
+					    "fd%d;fd;reserved;reserved;%s;",
+					    i, DEFAULT_DEV_ALLOC_AUTH);
+					(void) printf("%s%s\n", SECLIB,
+					    "/fd_clean");
+				}
+				break;
+			} else if (do_devmaps) {
+				/* print device_maps for floppy devices */
+				if (first) {
+					(void) printf(" ");
+				} else {
+					if (system_labeled) {
+						(void) printf("%s%d%s\\\n",
+						    dname, i, KV_TOKEN_DELIMIT);
+						(void) printf("\t%s%s\\\n",
+						    DA_FLOPPY_TYPE,
+						    KV_TOKEN_DELIMIT);
+						(void) printf("\t");
+					} else {
+						(void) printf("fd%d:\\\n", i);
+						(void) printf("\tfd:\\\n");
+						(void) printf("\t");
+					}
+					if (i == 0) {
+						(void) printf("/dev/diskette ");
+						(void) printf(
+						    "/dev/rdiskette ");
+					}
+					first++;
+				}
+				(void) printf("%s", fp[j].name);
+			}
 		}
-	    }
+		if (do_devmaps && first) {
+			(void) printf("\n\n");
+			first = 0;
+		}
+	}
+	if (do_files && floppy_count) {
+		dargs.rootdir = NULL;
+		dargs.devnames = NULL;
+		dargs.optflag = DA_ADD;
+		for (entry = devlist.floppy; entry != NULL;
+		    entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
+		}
 	}
 }
 
-static void
+static int
 docd()
 {
 	DIR *dirp;
 	struct dirent *dep;	/* directory entry pointer */
-	int	i, j, n;
+	int	i, j;
 	char	*nm;		/* name/device of special device */
 	char	linkvalue[2048];	/* symlink value */
 	struct stat stat;	/* determine if it's a symlink */
@@ -529,6 +806,11 @@
 	int	id;		/* disk id */
 	int	ctrl;		/* disk controller */
 	int	ncd;		/* max array size */
+	int	cd_count = 0;
+	int	first = 0;
+	char	*dname, *dclean;
+	da_args	dargs;
+	deventry_t *entry;
 
 	ncd = DFLT_NCD;
 
@@ -580,6 +862,7 @@
 		if ((sz = readlink(cd[i].name, linkvalue, sizeof (linkvalue))) <
 		    0)
 			continue;
+
 		nm = (char *)malloc(sz + 1);
 		if (nm == NULL)
 			no_memory();
@@ -593,7 +876,7 @@
 
 		i++;
 	}
-	n = i;
+	cd_count = i;
 
 	(void) closedir(dirp);
 
@@ -616,7 +899,7 @@
 			continue;
 
 		/* see if this is one of the cd special devices */
-		for (j = 0; j < n; j++) {
+		for (j = 0; j < cd_count; j++) {
 			if (cd[j].number == id && cd[j].controller == ctrl)
 				goto found;
 		}
@@ -667,7 +950,7 @@
 			continue;
 
 		/* see if this is one of the cd special devices */
-		for (j = 0; j < n; j++) {
+		for (j = 0; j < cd_count; j++) {
 			if (cd[j].number == id && cd[j].controller == ctrl)
 				goto found1;
 		}
@@ -701,18 +984,255 @@
 
 	(void) closedir(dirp);
 
-	n = i;
+	cd_count = i;
 
-	/* print out device_maps entries for tape devices */
+	if (system_labeled) {
+		dname = DA_CD_NAME;
+		dclean = DA_DEFAULT_DISK_CLEAN;
+	} else {
+		dname = "sr";
+		dclean = CD_CLEAN;
+	}
 	for (i = 0; i < 8; i++) {
-		for (j = 0; j < n; j++) {
-			if (cd[j].id == i) {
-				(void) printf(
-					"sr%d;sr;reserved;reserved;%s;",
-					i, DEFAULT_DEV_ALLOC_AUTH);
-				(void) printf("%s%s\n", SECLIB, "/sr_clean");
+		for (j = 0; j < cd_count; j++) {
+			if (cd[j].id != i)
+				continue;
+			if (do_files) {
+				(void) da_add_list(&devlist, cd[j].name, i,
+				    DA_CD);
+			} else if (do_devalloc) {
+				/* print device_allocate for cd devices */
+				if (system_labeled) {
+					(void) printf("%s%d%s\\\n",
+					    dname, i, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_CD_TYPE, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DA_RESERVED, KV_DELIMITER);
+					(void) printf("\t%s%s\\\n",
+					    DEFAULT_DEV_ALLOC_AUTH,
+					    KV_DELIMITER);
+					(void) printf("\t%s\n\n", dclean);
+				} else {
+					(void) printf(
+					    "sr%d;sr;reserved;reserved;%s;",
+					    i, DEFAULT_DEV_ALLOC_AUTH);
+					(void) printf("%s%s\n", SECLIB,
+					    "/sr_clean");
+				}
+				break;
+			} else if (do_devmaps) {
+				/* print device_maps for cd devices */
+				if (first) {
+					(void) printf(" ");
+				} else {
+					if (system_labeled) {
+						(void) printf("%s%d%s\\\n",
+						    dname, i, KV_TOKEN_DELIMIT);
+						(void) printf("\t%s%s\\\n",
+						    DA_CD_TYPE,
+						    KV_TOKEN_DELIMIT);
+						(void) printf("\t");
+					} else {
+						(void) printf("sr%d:\\\n", i);
+						(void) printf("\tsr:\\\n");
+						(void) printf("\t");
+					}
+					first++;
+				}
+				(void) printf("%s", cd[j].name);
+			}
+		}
+		if (do_devmaps && first) {
+			(void) printf("\n\n");
+			first = 0;
+		}
+	}
+	if (do_files && cd_count) {
+		dargs.rootdir = NULL;
+		dargs.devnames = NULL;
+		dargs.optflag = DA_ADD;
+		for (entry = devlist.cd; entry != NULL; entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
+		}
+	}
+
+	return (cd_count);
+}
+
+static void
+dormdisk(int cd_count)
+{
+	DIR *dirp;
+	struct dirent *dep;	/* directory entry pointer */
+	int	i, j;
+	char	*nm;		/* name/device of special device */
+	int	id;		/* disk id */
+	int	ctrl;		/* disk controller */
+	int	nrmdisk;	/* max array size */
+	int	fd = -1;
+	int	rmdisk_count;
+	int	first = 0;
+	int	is_cd;
+	int	checked;
+	int	removable;
+	char	path[MAXPATHLEN];
+	da_args	dargs;
+	deventry_t *entry;
+
+	nrmdisk = DFLT_RMDISK;
+	i = rmdisk_count = 0;
+
+	/*
+	 * scan /dev/dsk for rmdisk devices
+	 */
+	if ((dirp = opendir("/dev/dsk")) == NULL) {
+		perror("gettext(open /dev/dsk failure)");
+		exit(1);
+	}
+
+	while (dep = readdir(dirp)) {
+		is_cd = 0;
+		checked = 0;
+		removable = 0;
+		/* skip . .. etc... */
+		if (strncmp(dep->d_name, ".", 1) == NULL)
+			continue;
+
+		/* get device # (disk #) */
+		if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) <= 0)
+			continue;
+
+		/* see if we've already examined this device */
+		for (j = 0; j < i; j++) {
+			if (id == rmdisk[j].id &&
+			    ctrl == rmdisk[j].controller &&
+			    (strcmp(dep->d_name, rmdisk[j].name) == 0)) {
+				checked = 1;
 				break;
 			}
+			if (id == rmdisk[j].id && ctrl != rmdisk[j].controller)
+				/*
+				 * c2t0d0s0 is a different rmdisk than c3t0d0s0.
+				 */
+				id = rmdisk[j].id + 1;
+		}
+		if (checked)
+			continue;
+
+		/* ignore if this is a cd */
+		for (j = 0; j < cd_count; j++) {
+			if (id == cd[j].number && ctrl == cd[j].controller) {
+				is_cd = 1;
+				break;
+			}
+		}
+		if (is_cd)
+			continue;
+
+		/* see if device is removable */
+		(void) snprintf(path, sizeof (path), "%s%s", "/dev/rdsk/",
+		    dep->d_name);
+		if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
+			continue;
+		(void) ioctl(fd, DKIOCREMOVABLE, &removable);
+		(void) close(fd);
+		if (removable == 0)
+			continue;
+
+		/*
+		 * add new entry to table (/dev/dsk + / + d_name + \0)
+		 * if array full, then expand it
+		 */
+		if (i == nrmdisk) {
+			/* will exit(1) if insufficient memory */
+			nrmdisk = expandmem(i, (void **)&rmdisk,
+			    sizeof (struct rmdisk));
+		}
+		nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1);
+		if (nm == NULL)
+			no_memory();
+		(void) strcpy(nm, "/dev/dsk/");
+		(void) strcat(nm, dep->d_name);
+		rmdisk[i].name = nm;
+		rmdisk[i].id = id;
+		rmdisk[i].controller = ctrl;
+		rmdisk[i].device = "";
+		rmdisk[i].number = id;
+		rmdisk_r[i].name = strdup(path);
+		i++;
+	}
+
+	rmdisk_count = i;
+	(void) closedir(dirp);
+
+	for (i = 0, j = rmdisk_count; i < rmdisk_count; i++, j++) {
+		if (j == nrmdisk) {
+			/* will exit(1) if insufficient memory */
+			nrmdisk = expandmem(j, (void **)&rmdisk,
+			    sizeof (struct rmdisk));
+		}
+		rmdisk[j].name = rmdisk_r[i].name;
+		rmdisk[j].id = rmdisk[i].id;
+		rmdisk[j].controller = rmdisk[i].controller;
+		rmdisk[j].device = rmdisk[i].device;
+		rmdisk[j].number = rmdisk[i].number;
+	}
+	rmdisk_count = j;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 0; j < rmdisk_count; j++) {
+			if (rmdisk[j].id != i)
+				continue;
+			if (do_files) {
+				(void) da_add_list(&devlist, rmdisk[j].name, i,
+				    DA_RMDISK);
+			} else if (do_devalloc) {
+				/* print device_allocate for rmdisk devices */
+				(void) printf("%s%d%s\\\n",
+				    DA_RMDISK_NAME, i, KV_DELIMITER);
+				(void) printf("\t%s%s\\\n",
+				    DA_RMDISK_TYPE, KV_DELIMITER);
+				(void) printf("\t%s%s\\\n",
+				    DA_RESERVED, KV_DELIMITER);
+				(void) printf("\t%s%s\\\n",
+				    DA_RESERVED, KV_DELIMITER);
+				(void) printf("\t%s%s\\\n",
+				    DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER);
+				(void) printf("\t%s\n", DA_DEFAULT_DISK_CLEAN);
+				break;
+			} else if (do_devmaps) {
+				/* print device_maps for rmdisk devices */
+				if (first) {
+					(void) printf(" ");
+				} else {
+					(void) printf("%s%d%s\\\n",
+					    DA_RMDISK_NAME, i,
+					    KV_TOKEN_DELIMIT);
+					(void) printf("\t%s%s\\\n",
+					    DA_RMDISK_TYPE, KV_TOKEN_DELIMIT);
+					(void) printf("\t");
+					first++;
+				}
+				(void) printf("%s", rmdisk[j].name);
+			}
+		}
+		if (do_devmaps && first) {
+			(void) printf("\n\n");
+			first = 0;
+		}
+	}
+	if (do_files && rmdisk_count) {
+		dargs.rootdir = NULL;
+		dargs.devnames = NULL;
+		dargs.optflag = DA_ADD;
+		for (entry = devlist.rmdisk; entry != NULL;
+		    entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
 		}
 	}
 }
@@ -725,9 +1245,22 @@
 	audio = (struct audio *)calloc(DFLT_NAUDIO, sizeof (struct audio));
 	cd    = (struct cd *)calloc(DFLT_NCD, sizeof (struct cd));
 	fp    = (struct fp *)calloc(DFLT_NFP, sizeof (struct fp));
+	if (system_labeled) {
+		rmdisk = (struct rmdisk *)calloc(DFLT_RMDISK,
+		    sizeof (struct rmdisk));
+		if (rmdisk == NULL)
+			no_memory();
+		rmdisk_r = (struct rmdisk *)calloc(DFLT_RMDISK,
+		    sizeof (struct rmdisk));
+		if (rmdisk_r == NULL)
+			no_memory();
+	}
 
 	if (tape == NULL || audio == NULL || cd == NULL || fp == NULL)
 		no_memory();
+
+	devlist.audio = devlist.cd = devlist.floppy = devlist.rmdisk =
+	    devlist.tape = NULL;
 }
 
 /* note n will be # elments in array (and could be 0) */
--- a/usr/src/cmd/auditconfig/auditconfig.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditconfig/auditconfig.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,6 +51,7 @@
 #include <pwd.h>
 #include <libintl.h>
 #include <zone.h>
+#include <tsol/label.h>
 
 #include <bsm/audit.h>
 #include <bsm/audit_record.h>
@@ -117,6 +117,10 @@
 #define	AC_KERN_EVENT 		0
 #define	AC_USER_EVENT 		1
 
+/* defines for policy entry flags: */
+
+#define	AC_TSOL 		1	/* policy is TSOL-only */
+
 #define	NONE(s) (!strlen(s) ? gettext("none") : s)
 
 #define	ALL_POLICIES   (AUDIT_AHLT|\
@@ -131,7 +135,9 @@
 			AUDIT_PATH|\
 			AUDIT_PUBLIC|\
 			AUDIT_ZONENAME|\
-			AUDIT_PERZONE)
+			AUDIT_PERZONE|\
+			AUDIT_WINDATA_DOWN|\
+			AUDIT_WINDATA_UP)
 
 #define	NO_POLICIES  (0)
 
@@ -153,6 +159,7 @@
 struct policy_entry {
 	char *policy_str;
 	uint_t policy_mask;
+	uint_t policy_flags;
 	char *policy_desc;
 };
 
@@ -236,27 +243,40 @@
 #define	ARG2_TBL_SZ (sizeof (arg2_table) / sizeof (struct arg_entry))
 
 static struct policy_entry policy_table[] = {
-	{"ahlt",  AUDIT_AHLT,   "halt machine if it can not record an "
-	    "async event"},
-	{"arge",  AUDIT_ARGE,   "include exec environment args in audit recs"},
-	{"argv",  AUDIT_ARGV,   "include exec command line args in audit recs"},
-	{"cnt",   AUDIT_CNT,    "when no more space, drop recs and keep a cnt"},
-	{"group", AUDIT_GROUP,  "include supplementary groups in audit recs"},
-	{"seq",   AUDIT_SEQ,    "include a sequence number in audit recs"},
-	{"trail", AUDIT_TRAIL,  "include trailer token in audit recs"},
-	{"path",  AUDIT_PATH,   "allow multiple paths per event"},
-	{"public",  AUDIT_PUBLIC,   "audit public files"},
-	{"zonename", AUDIT_ZONENAME,    "generate zonename token"},
-	{"perzone", AUDIT_PERZONE,	"use a separate queue and auditd per "
-	    "zone"},
-	{"all",   ALL_POLICIES, "all policies"},
-	{"none",  NO_POLICIES,  "no policies"}
+	{"ahlt",	AUDIT_AHLT,	NULL,
+	    "halt machine if it can not record an async event"},
+	{"arge",	AUDIT_ARGE,	NULL,
+	    "include exec environment args in audit recs"},
+	{"argv",	AUDIT_ARGV,	NULL,
+	    "include exec command line args in audit recs"},
+	{"cnt",		AUDIT_CNT,	NULL,
+	    "when no more space, drop recs and keep a cnt"},
+	{"group",	AUDIT_GROUP,	NULL,
+	    "include supplementary groups in audit recs"},
+	{"path",	AUDIT_PATH,	NULL,
+	    "allow multiple paths per event"},
+	{"public",	AUDIT_PUBLIC,	NULL,	"audit public files"},
+	{"seq",		AUDIT_SEQ,	NULL,
+	    "include a sequence number in audit recs"},
+	{"trail",	AUDIT_TRAIL,	NULL,
+	    "include trailer token in audit recs"},
+	{"windata_down",	AUDIT_WINDATA_DOWN,	AC_TSOL,
+		"include downgraded information in audit recs"},
+	{"windata_up",		AUDIT_WINDATA_UP,	AC_TSOL,
+		"include upgraded information in audit recs"},
+	{"zonename",	AUDIT_ZONENAME,	NULL,	"generate zonename token"},
+	{"perzone",	AUDIT_PERZONE,	NULL,
+	    "use a separate queue and auditd per zone"},
+	{"all",		ALL_POLICIES,	NULL,	"all policies"},
+	{"none",	NO_POLICIES,	NULL,	"no policies"}
 	};
 
 #define	POLICY_TBL_SZ (sizeof (policy_table) / sizeof (struct policy_entry))
 
 static char *progname;
 
+int	tsol_on;			/* is TSOL installed? */
+
 static au_event_ent_t *egetauevnam();
 static au_event_ent_t *egetauevnum();
 static char *strtolower();
@@ -368,6 +388,8 @@
 		strcmp(argv[1], "-?") == 0))
 		exit_usage(0);
 
+	tsol_on = is_system_labeled();
+
 	parse_args(argv);
 
 	do_args(argv);
@@ -1246,6 +1268,15 @@
 				"Could not allocate subject token\n"));
 		if (au_write(rd, tokp) == -1)
 exit_error(gettext("Could not construct subject token of audit record\n"));
+
+		if (tsol_on) {
+			if ((tokp = au_to_mylabel()) == (token_t *)NULL)
+				exit_error(gettext(
+				    "Could not allocate slabel token\n"));
+			if (au_write(rd, tokp) == -1)
+exit_error(gettext("Could not construct slabel token of audit record\n"));
+		}
+
 		if ((tokp = au_to_text(audit_str)) == (token_t *)NULL)
 			exit_error(gettext("Could not allocate text token\n"));
 		if (au_write(rd, tokp) == -1)
@@ -1634,10 +1665,12 @@
 	 *	Print a properly aligned header.
 	 */
 	(void) printf(gettext("policy string    description:\n"));
-	for (i = 0; i < POLICY_TBL_SZ; i++)
-		(void) printf("%-17s%s\n",
-			policy_table[i].policy_str,
-			gettext(policy_table[i].policy_desc));
+	for (i = 0; i < POLICY_TBL_SZ; i++) {
+		if ((policy_table[i].policy_flags & AC_TSOL) && !tsol_on)
+			continue;	/* skip this entry */
+		(void) printf("%-17s%s\n", policy_table[i].policy_str,
+		    gettext(policy_table[i].policy_desc));
+	}
 }
 
 static void
@@ -2295,10 +2328,12 @@
 {
 	int i;
 
-	for (i = 0; i < POLICY_TBL_SZ; i++)
-		if (strcmp(strtolower(policy),
-			policy_table[i].policy_str) == 0)
+	for (i = 0; i < POLICY_TBL_SZ; i++) {
+		if ((policy_table[i].policy_flags & AC_TSOL) && !tsol_on)
+			continue;	/* skip this entry */
+		if (strcmp(strtolower(policy), policy_table[i].policy_str) == 0)
 			return (&policy_table[i]);
+	}
 
 	return ((struct policy_entry *)NULL);
 }
@@ -2389,7 +2424,9 @@
 
 	*policy_str = '\0';
 
-	for (i = 0, j = 0; i < POLICY_TBL_SZ; i++)
+	for (i = 0, j = 0; i < POLICY_TBL_SZ; i++) {
+		if ((policy_table[i].policy_flags & AC_TSOL) && !tsol_on)
+			continue;	/* skip this entry */
 		if (policy & policy_table[i].policy_mask &&
 		    policy_table[i].policy_mask != ALL_POLICIES) {
 			if (j++)
@@ -2397,6 +2434,7 @@
 			(void) strlcat(policy_str,
 			    policy_table[i].policy_str, len);
 		}
+	}
 
 	if (*policy_str)
 		return (0);
--- a/usr/src/cmd/auditreduce/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -39,7 +40,9 @@
 POFILES=main.po option.po proc.po time.po token.po
 
 CPPFLAGS += -I$(TABLEDIR) -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-LDLIBS += -lnsl -lbsm
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += -lnsl -lbsm  $(LAZYLIBS)
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/auditreduce/auditr.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/auditr.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1987 - 2000 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef _AUDITR_H
@@ -62,6 +61,9 @@
 #include <bsm/audit_record.h>
 #include <bsm/libbsm.h>
 
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
 #include "auditrt.h"
 
 /*
--- a/usr/src/cmd/auditreduce/auditrd.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/auditrd.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,9 +50,7 @@
 time_t	m_before;		/* 'b' before a time */
 audit_state_t mask;		/* used with m_class */
 char	*zonename;		/* 'z' zonename */
-#ifdef	TSOL
-brange_t m_label;		/* 'l' mandatory label range */
-#endif	/* TSOL */
+m_range_t *m_label;		/* 'l' mandatory label range */
 int	flags;
 int	checkflags;
 int	socket_flag;
--- a/usr/src/cmd/auditreduce/auditrt.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/auditrt.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -175,9 +174,7 @@
 extern audit_state_t mask;	/* used with m_class */
 extern char	*zonename;	/* 'z' zonename */
 
-#ifdef	TSOL
-extern brange_t m_label;	/* 'l' mandatory label range */
-#endif	/* TSOL */
+extern m_range_t *m_label;	/* 'l' mandatory label range */
 extern int	flags;
 extern int	checkflags;
 extern int	socket_flag;
--- a/usr/src/cmd/auditreduce/option.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/option.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,11 +33,6 @@
 
 #include <locale.h>
 #include <sys/zone.h>	/* for max zonename length */
-
-#ifdef	TSOL
-#include <tsol/label.h>
-#endif	/* TSOL */
-
 #include "auditr.h"
 
 /*
@@ -95,9 +89,7 @@
 static int	proc_id(char *, int);
 static int	proc_object(char *);
 static void	proc_pcb(audit_pcb_t *, char *, int);
-#ifdef	TSOL
 static int	proc_slabel(char *);
-#endif	/* TSOL */
 static int	proc_subject(char *);
 static int	proc_sid(char *);
 static int	proc_type(char *);
@@ -203,12 +195,16 @@
 			if (proc_id(optarg, opt))
 				error = TRUE;
 			break;
-#ifdef	TSOL
 		case 'l':		/* label range -- reserved for TX */
+			if (!is_system_labeled()) {
+				(void) fprintf(stderr,
+				    gettext("%s option 'l' requires "
+				    "Trusted Extensions.\n"), ar);
+				return (-1);
+			}
 			if (proc_slabel(optarg))
 				error = TRUE;
 			break;
-#endif	/* TSOL */
 		case 's':		/* session ID */
 			if (proc_sid(optarg))
 				error = TRUE;
@@ -1137,7 +1133,6 @@
 }
 
 
-#ifdef	TSOL
 /*
  * .func	proc_slabel - process sensitivity label range argument.
  * .desc	Parse sensitivity label range sl:sl
@@ -1157,67 +1152,101 @@
 		error_str = gettext("'l' option specified multiple times");
 		return (-1);
 	}
+	flags |= M_LABEL;
 
-	flags |= M_LABEL;
-	p = strchr(optstr, ':');
+	if ((m_label = malloc(sizeof (m_range_t))) == NULL) {
+		return (-1);
+	}
+	m_label->lower_bound = NULL;
+	m_label->upper_bound = NULL;
+
+	p = strchr(optstr, ';');
 	if (p == NULL) {
 		/* exact label match, lower and upper range bounds the same */
-		if (stobsl(optstr, &m_slabel.lower_bound, NO_CORRECTION,
-		    &error) == 0) {
+		if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
+		    L_NO_CORRECTION, &error) == -1) {
 			(void) sprintf(errbuf,
 			    gettext("invalid sensitivity label (%s) err %d"),
 			    optstr, error);
 			error_str = errbuf;
-			return (-1);
+			goto errout;
 		}
-		m_slabel.upper_bound = m_slabel.lower_bound;
+		m_label->upper_bound = m_label->lower_bound;
 		return (0);
 	}
 	if (p == optstr) {
 		/* lower bound is not specified .. default is admin_low */
-		bsllow(&m_slabel.lower_bound);
-		if (stobsl(p + 1, &m_slabel.upper_bound, NO_CORRECTION,
-		    &error) == 0) {
-			(void) sprintf(errbuf,
-			    gettext("invalid sensitivity label (%s) err %d"),
-			    p + 1, error);
-			error_str = errbuf;
+		if (str_to_label(ADMIN_LOW, &m_label->lower_bound, MAC_LABEL,
+		    L_NO_CORRECTION, &error) == -1) {
+			free(m_label);
 			return (-1);
 		}
+
+		p++;
+		if (*p == '\0') {
+			/* upper bound not specified .. default is admin_high */
+			if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
+			    MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
+				m_label_free(m_label->lower_bound);
+				free(m_label);
+				return (-1);
+			}
+		} else {
+			if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
+			    L_NO_CORRECTION, &error) == -1) {
+				(void) sprintf(errbuf, gettext(
+				    "invalid sensitivity label (%s) err %d"),
+				    p, error);
+				error_str = errbuf;
+				goto errout;
+			}
+		}
 		return (0);
 	}
 	*p++ = '\0';
-	if (stobsl(optstr, &m_slabel.lower_bound, NO_CORRECTION, &error) == 0) {
+	if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
+	    L_NO_CORRECTION, &error) == -1) {
 		(void) sprintf(errbuf,
 		    gettext("invalid sensitivity label (%s) err %d"), optstr,
 		    error);
 		error_str = errbuf;
-		return (-1);
+		goto errout;
 	}
-	if (*p == '\0')
+	if (*p == '\0') {
 		/* upper bound is not specified .. default is admin_high */
-		bslhigh(&m_slabel.upper_bound);
-	else {
-		if (stobsl(p, &m_slabel.upper_bound, NO_CORRECTION, &error) ==
-		    0) {
+		if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
+		    MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
+			m_label_free(m_label->lower_bound);
+			free(m_label);
+			return (-1);
+		}
+	} else {
+		if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
+		    L_NO_CORRECTION, &error) == -1) {
 			(void) sprintf(errbuf,
 			    gettext("invalid sensitivity label (%s) err %d"),
 			    p, error);
 			error_str = errbuf;
-			return (-1);
+			goto errout;
 		}
 	}
 	/* make sure that upper bound dominates the lower bound */
-	if (!bldominates(&m_slabel.upper_bound, &m_slabel.lower_bound)) {
-		*--p = ':';
+	if (!bldominates(m_label->upper_bound, m_label->lower_bound)) {
+		*--p = ';';
 		(void) sprintf(errbuf,
 		    gettext("invalid sensitivity label range (%s)"), optstr);
 		error_str = errbuf;
-		return (-1);
+		goto errout;
 	}
 	return (0);
+
+errout:
+	m_label_free(m_label->upper_bound);
+	m_label_free(m_label->lower_bound);
+	free(m_label);
+
+	return (-1);
 }
-#endif	/* !TSOL */
 
 /*
  * proc_zonename - pick up zone name.
--- a/usr/src/cmd/auditreduce/token.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/auditreduce/token.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1868,48 +1867,6 @@
 }
 
 /*
- * Format of clearance token:
- *	clearance		adr_char*(sizeof (bclear_t))
- */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
-int
-clearance_token(adr_t *adr)
-{
-#ifdef	TSOL
-	bclear_t clearance;
-
-	adrm_char(adr, (char *)&clearance, sizeof (bclear_t));
-	return (-1);
-#else	/* !TSOL */
-	return (-2);
-#endif	/* TSOL */
-}
-
-
-/*
- * Format of ilabel token:
- *	ilabel			adr_char*(sizeof (bilabel_t))
- */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
-int
-ilabel_token(adr_t *adr)
-{
-#ifdef	TSOL
-	bilabel_t ilabel;
-
-	adrm_char(adr, (char *)&ilabel, sizeof (ilabel));
-
-	return (-1);
-#else	/* !TSOL */
-	return (-2);
-#endif	/* TSOL */
-}
-
-/*
  * Format of privilege set token:
  *	priv_set type		string
  *	priv_set		string
@@ -1927,26 +1884,19 @@
  * Format of slabel token:
  *	slabel			adr_char*(sizeof (bslabel_t))
  */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
 int
 slabel_token(adr_t *adr)
 {
-#ifdef	TSOL
 	bslabel_t slabel;
 
 	adrm_char(adr, (char *)&slabel, sizeof (slabel));
 
-	if (flags & M_SLABEL) {
-		if (blinrange(&slabel, &m_slabel))
-			checkflags = checkflags | M_SLABEL;
+	if (flags & M_LABEL) {
+		if (blinrange(&slabel, m_label))
+			checkflags = checkflags | M_LABEL;
 	}
 
 	return (-1);
-#else	/* !TSOL */
-	return (-2);
-#endif	/* TSOL */
 }
 
 
--- a/usr/src/cmd/bsmconv/bsmconv.sh	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/bsmconv/bsmconv.sh	Fri Mar 24 12:29:20 2006 -0800
@@ -1,11 +1,11 @@
 #! /bin/sh
 #
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,8 +20,7 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -143,18 +142,25 @@
     printf "${form}\n" $PROG
 fi
 
-# Initial device allocation files
+# Initialize device allocation
 
-form=`gettext "%s: INFO: initializing device allocation files."`
+form=`gettext "%s: INFO: initializing device allocation."`
 printf "${form}\n" $PROG
-if [ ! -f ${ROOT}/$DEVALLOC ]
+if [ -x /usr/bin/plabel ]
 then
-	mkdevalloc > ${ROOT}/$DEVALLOC
+	# Trusted Extensions is installed.
+	/usr/sbin/devfsadm -e
+else
+	if [ ! -f ${ROOT}/${DEVALLOC} ]
+	then
+		mkdevalloc > ${ROOT}/$DEVALLOC
+	fi
+	if [ ! -f ${ROOT}/${DEVMAPS} ]
+	then
+		mkdevmaps > ${ROOT}/$DEVMAPS
+	fi
 fi
-if [ ! -f $DEVMAPS ]
-then
-	mkdevmaps > ${ROOT}/$DEVMAPS
-fi
+
 
 # enable auditd.  Since we're running as single user, auditd won't
 # actually start until reboot.
--- a/usr/src/cmd/bsmunconv/bsmunconv.sh	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/bsmunconv/bsmunconv.sh	Fri Mar 24 12:29:20 2006 -0800
@@ -1,11 +1,12 @@
 #! /bin/sh
 #
+#
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,8 +21,7 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -84,8 +84,7 @@
 bsmunconvert()
 {
 
-# deallocate user allocatable devices and turn off device allocation
-/usr/sbin/deallocate -Is
+# turn off device allocation
 /usr/sbin/devfsadm -d
 
 # disable auditd service
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,11 +17,13 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 1996-2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Copyright (c) 1990 Mentat Inc.
@@ -43,8 +44,9 @@
 SRCS=		$(LOCALSRCS) $(COMMONSRCS)
 
 CPPFLAGS += -DNDEBUG -I$(CMDINETCOMMONDIR)
-LDLIBS += -ldhcpagent -lcmd -lsocket -lnsl -lkstat
-LINTFLAGS += -m
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += -ldhcpagent -lcmd -lsocket -lnsl -lkstat -ltsnet $(LAZYLIBS)
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,7 +65,6 @@
 #include <sys/stream.h>
 #include <stropts.h>
 #include <sys/strstat.h>
-#include <sys/sysmacros.h>
 #include <sys/tihdr.h>
 
 #include <sys/socket.h>
@@ -94,9 +92,10 @@
 #include <dhcpagent_util.h>
 #include <compat.h>
 
+#include <libtsnet.h>
+#include <tsol/label.h>
+
 extern void	unixpr(kstat_ctl_t *kc);
-extern void	setifdhcp(const char *caller, const char *ifname,
-		    int argc, char *argv[]);
 
 #define	STR_EXPAND	4
 
@@ -141,7 +140,7 @@
 static void		mib_item_destroy(mib_item_t **item);
 
 static boolean_t	octetstrmatch(const Octet_t *a, const Octet_t *b);
-static char		*octetstr(Octet_t *op, int code,
+static char		*octetstr(const Octet_t *op, int code,
 			    char *dst, uint_t dstlen);
 static char		*pr_addr(uint_t addr,
 			    char *dst, uint_t dstlen);
@@ -150,8 +149,8 @@
 			    char *dst, uint_t dstlen);
 static char		*pr_mask(uint_t addr,
 			    char *dst, uint_t dstlen);
-static char		*pr_prefix6(struct in6_addr *addr, uint_t prefixlen,
-			    char *dst, uint_t dstlen);
+static char		*pr_prefix6(const struct in6_addr *addr,
+			    uint_t prefixlen, char *dst, uint_t dstlen);
 static char		*pr_ap(uint_t addr, uint_t port,
 			    char *proto, char *dst, uint_t dstlen);
 static char		*pr_ap6(const in6_addr_t *addr, uint_t port,
@@ -166,7 +165,10 @@
 static char		*portname(uint_t port, char *proto,
 			    char *dst, uint_t dstlen);
 
-static	char		*mitcp_state(int code);
+static const char	*mitcp_state(int code,
+			    const mib2_transportMLPEntry_t *attr);
+static const char	*miudp_state(int code,
+			    const mib2_transportMLPEntry_t *attr);
 
 static void		stat_report(mib_item_t *item);
 static void		mrt_stat_report(mib_item_t *item);
@@ -183,9 +185,9 @@
 static void		if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
 			    char ifname[], char logintname[],
 			    struct ifstat *statptr, boolean_t ksp_not_null);
-static void		ire_report(mib_item_t *item);
-static void		tcp_report(mib_item_t *item);
-static void		udp_report(mib_item_t *item);
+static void		ire_report(const mib_item_t *item);
+static void		tcp_report(const mib_item_t *item);
+static void		udp_report(const mib_item_t *item);
 static void		group_report(mib_item_t *item);
 static void		print_ip_stats(mib2_ip_t *ip);
 static void		print_icmp_stats(mib2_icmp_t *icmp);
@@ -197,7 +199,7 @@
 static void		print_rawip_stats(mib2_rawip_t *rawip);
 static void		print_igmp_stats(struct igmpstat *igps);
 static void		print_mrt_stats(struct mrtstat *mrts);
-static void		sctp_report(mib_item_t *item);
+static void		sctp_report(const mib_item_t *item);
 static void		sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
 			    mib2_ipv6IfStatsEntry_t *sum6);
 static void		sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
@@ -232,6 +234,7 @@
 static	boolean_t	Mflag = B_FALSE;	/* STREAMS Memory Statistics */
 static	boolean_t	Nflag = B_FALSE;	/* Numeric Network Addresses */
 static	boolean_t	Rflag = B_FALSE;	/* Routing Tables */
+static	boolean_t	RSECflag = B_FALSE;	/* Security attributes */
 static	boolean_t	Sflag = B_FALSE;	/* Per-protocol Statistics */
 static	boolean_t	Vflag = B_FALSE;	/* Verbose */
 static	boolean_t	Pflag = B_FALSE;	/* Net to Media Tables */
@@ -254,6 +257,7 @@
 static int ipNetToMediaEntrySize;
 static int ipMemberEntrySize;
 static int ipGroupSourceEntrySize;
+static int ipRouteAttributeSize;
 static int vifctlSize;
 static int mfcctlSize;
 
@@ -265,6 +269,7 @@
 static int ipv6MemberEntrySize;
 static int ipv6GroupSourceEntrySize;
 
+static int transportMLPSize;
 static int tcpConnEntrySize;
 static int tcp6ConnEntrySize;
 static int udpEntrySize;
@@ -362,7 +367,7 @@
 		    default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
 	free(default_ip_str);
 
-	while ((c = getopt(argc, argv, "adimnrspMgvf:P:I:D")) != -1) {
+	while ((c = getopt(argc, argv, "adimnrspMgvf:P:I:DR")) != -1) {
 		switch ((char)c) {
 		case 'a':		/* all connections */
 			Aflag = B_TRUE;
@@ -391,6 +396,11 @@
 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
 			break;
 
+		case 'R':		/* security attributes */
+			RSECflag = B_TRUE;
+			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+			break;
+
 		case 's':		/* per-protocol statistics */
 			Sflag = B_TRUE;
 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
@@ -467,6 +477,14 @@
 	}
 
 	/*
+	 * Make sure -R option is set only on a labeled system.
+	 */
+	if (RSECflag && !is_system_labeled()) {
+		(void) fprintf(stderr, "-R set but labeling is not enabled\n");
+		usage(name);
+	}
+
+	/*
 	 * Handle other arguments: find interval, count; the
 	 * flags that accept 'interval' and 'count' are OR'd
 	 * in the outermost 'if'; more flags may be added as
@@ -1460,7 +1478,7 @@
 
 /* If octetstr() changes make an appropriate change to STR_EXPAND */
 static char *
-octetstr(Octet_t *op, int code, char *dst, uint_t dstlen)
+octetstr(const Octet_t *op, int code, char *dst, uint_t dstlen)
 {
 	int	i;
 	char	*cp;
@@ -1504,11 +1522,11 @@
 	return (dst);
 }
 
-static char *
-mitcp_state(int state)
+static const char *
+mitcp_state(int state, const mib2_transportMLPEntry_t *attr)
 {
-static	char	tcpsbuf[50];
-	char	*cp;
+	static char tcpsbuf[50];
+	const char *cp;
 
 	switch (state) {
 	case TCPS_CLOSED:
@@ -1556,6 +1574,55 @@
 		cp = tcpsbuf;
 		break;
 	}
+
+	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
+		if (cp != tcpsbuf) {
+			(void) strlcpy(tcpsbuf, cp, sizeof (tcpsbuf));
+			cp = tcpsbuf;
+		}
+		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
+			(void) strlcat(tcpsbuf, " P", sizeof (tcpsbuf));
+		if (attr->tme_flags & MIB2_TMEF_SHARED)
+			(void) strlcat(tcpsbuf, " S", sizeof (tcpsbuf));
+	}
+
+	return (cp);
+}
+
+static const char *
+miudp_state(int state, const mib2_transportMLPEntry_t *attr)
+{
+	static char udpsbuf[50];
+	const char *cp;
+
+	switch (state) {
+	case MIB2_UDP_unbound:
+		cp = "Unbound";
+		break;
+	case MIB2_UDP_idle:
+		cp = "Idle";
+		break;
+	case MIB2_UDP_connected:
+		cp = "Connected";
+		break;
+	default:
+		(void) snprintf(udpsbuf, sizeof (udpsbuf),
+		    "Unknown State(%d)", state);
+		cp = udpsbuf;
+		break;
+	}
+
+	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
+		if (cp != udpsbuf) {
+			(void) strlcpy(udpsbuf, cp, sizeof (udpsbuf));
+			cp = udpsbuf;
+		}
+		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
+			(void) strlcat(udpsbuf, " P", sizeof (udpsbuf));
+		if (attr->tme_flags & MIB2_TMEF_SHARED)
+			(void) strlcat(udpsbuf, " S", sizeof (udpsbuf));
+	}
+
 	return (cp);
 }
 
@@ -1637,6 +1704,8 @@
 			ipNetToMediaEntrySize = ip->ipNetToMediaEntrySize;
 			ipMemberEntrySize = ip->ipMemberEntrySize;
 			ipGroupSourceEntrySize = ip->ipGroupSourceEntrySize;
+			ipRouteAttributeSize = ip->ipRouteAttributeSize;
+			transportMLPSize = ip->transportMLPSize;
 			assert(IS_P2ALIGNED(ipAddrEntrySize,
 			    sizeof (mib2_ipAddrEntry_t *)) &&
 			    IS_P2ALIGNED(ipRouteEntrySize,
@@ -1646,7 +1715,11 @@
 			    IS_P2ALIGNED(ipMemberEntrySize,
 				sizeof (ip_member_t *)) &&
 			    IS_P2ALIGNED(ipGroupSourceEntrySize,
-				sizeof (ip_grpsrc_t *)));
+				sizeof (ip_grpsrc_t *)) &&
+			    IS_P2ALIGNED(ipRouteAttributeSize,
+				sizeof (mib2_ipAttributeEntry_t *)) &&
+			    IS_P2ALIGNED(transportMLPSize,
+				sizeof (mib2_transportMLPEntry_t *)));
 			break;
 		}
 		case EXPER_DVMRP: {
@@ -1737,6 +1810,8 @@
 		(void) printf("\tipNetToMediaEntrySize %d\n",
 		    ipNetToMediaEntrySize);
 		(void) printf("\tipMemberEntrySize %d\n", ipMemberEntrySize);
+		(void) printf("\tipRouteAttributeSize %d\n",
+		    ipRouteAttributeSize);
 		(void) printf("\tvifctlSize %d\n", vifctlSize);
 		(void) printf("\tmfcctlSize %d\n", mfcctlSize);
 
@@ -1748,6 +1823,7 @@
 		    ipv6MemberEntrySize);
 		(void) printf("\tipv6IfIcmpEntrySize %d\n",
 		    ipv6IfIcmpEntrySize);
+		(void) printf("\ttransportMLPSize %d\n", transportMLPSize);
 		(void) printf("\ttcpConnEntrySize %d\n", tcpConnEntrySize);
 		(void) printf("\ttcp6ConnEntrySize %d\n", tcp6ConnEntrySize);
 		(void) printf("\tudpEntrySize %d\n", udpEntrySize);
@@ -3656,23 +3732,102 @@
 
 /* ------------------------- ire_report (netstat -r) ------------------------ */
 
-static boolean_t ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first);
-static boolean_t ire_report_item_v4src(mib2_ipRouteEntry_t *rp,
-    boolean_t first);
-static boolean_t ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6,
-    boolean_t first);
+typedef struct sec_attr_list_s {
+	struct sec_attr_list_s *sal_next;
+	const mib2_ipAttributeEntry_t *sal_attr;
+} sec_attr_list_t;
+
+static boolean_t ire_report_item_v4(const mib2_ipRouteEntry_t *, boolean_t,
+    const sec_attr_list_t *);
+static boolean_t ire_report_item_v4src(const mib2_ipRouteEntry_t *, boolean_t,
+    const sec_attr_list_t *);
+static boolean_t ire_report_item_v6(const mib2_ipv6RouteEntry_t *, boolean_t,
+    const sec_attr_list_t *);
+static const char *pr_secattr(const sec_attr_list_t *);
 
 static void
-ire_report(mib_item_t *item)
+ire_report(const mib_item_t *item)
 {
 	int			jtemp = 0;
 	boolean_t		print_hdr_once_v4 = B_TRUE;
 	boolean_t		print_hdr_once_v6 = B_TRUE;
 	mib2_ipRouteEntry_t	*rp;
 	mib2_ipv6RouteEntry_t	*rp6;
+	sec_attr_list_t		**v4_attrs, **v4a;
+	sec_attr_list_t		**v6_attrs, **v6a;
+	sec_attr_list_t		*all_attrs, *aptr;
+	const mib_item_t	*iptr;
+	int			ipv4_route_count, ipv6_route_count;
+	int			route_attrs_count;
+
+	/*
+	 * Preparation pass: the kernel returns separate entries for IP routing
+	 * table entries and security attributes.  We loop through the
+	 * attributes first and link them into lists.
+	 */
+	ipv4_route_count = ipv6_route_count = route_attrs_count = 0;
+	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
+		if (iptr->group == MIB2_IP6 && iptr->mib_id == MIB2_IP6_ROUTE)
+			ipv6_route_count += iptr->length / ipv6RouteEntrySize;
+		if (iptr->group == MIB2_IP && iptr->mib_id == MIB2_IP_ROUTE)
+			ipv4_route_count += iptr->length / ipRouteEntrySize;
+		if ((iptr->group == MIB2_IP || iptr->group == MIB2_IP6) &&
+		    iptr->mib_id == EXPER_IP_RTATTR)
+			route_attrs_count += iptr->length /
+			    ipRouteAttributeSize;
+	}
+	v4_attrs = v6_attrs = NULL;
+	all_attrs = NULL;
+	if (family_selected(AF_INET) && ipv4_route_count > 0) {
+		v4_attrs = calloc(ipv4_route_count, sizeof (*v4_attrs));
+		if (v4_attrs == NULL) {
+			perror("ire_report calloc v4_attrs failed");
+			return;
+		}
+	}
+	if (family_selected(AF_INET6) && ipv6_route_count > 0) {
+		v6_attrs = calloc(ipv6_route_count, sizeof (*v6_attrs));
+		if (v6_attrs == NULL) {
+			perror("ire_report calloc v6_attrs failed");
+			goto ire_report_done;
+		}
+	}
+	if (route_attrs_count > 0) {
+		all_attrs = malloc(route_attrs_count * sizeof (*all_attrs));
+		if (all_attrs == NULL) {
+			perror("ire_report malloc all_attrs failed");
+			goto ire_report_done;
+		}
+	}
+	aptr = all_attrs;
+	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
+		mib2_ipAttributeEntry_t *iae;
+		sec_attr_list_t **alp;
+
+		if (v4_attrs != NULL && iptr->group == MIB2_IP &&
+		    iptr->mib_id == EXPER_IP_RTATTR) {
+			alp = v4_attrs;
+		} else if (v6_attrs != NULL && iptr->group == MIB2_IP6 &&
+		    iptr->mib_id == EXPER_IP_RTATTR) {
+			alp = v6_attrs;
+		} else {
+			continue;
+		}
+		for (iae = iptr->valp;
+		    (char *)iae < (char *)iptr->valp + iptr->length;
+		    /* LINTED: (note 1) */
+		    iae = (mib2_ipAttributeEntry_t *)((char *)iae +
+		    ipRouteAttributeSize)) {
+			aptr->sal_next = alp[iae->iae_routeidx];
+			aptr->sal_attr = iae;
+			alp[iae->iae_routeidx] = aptr++;
+		}
+	}
 
 	/* 'for' loop 1: */
-	for (; item; item = item->next_item) {
+	v4a = v4_attrs;
+	v6a = v6_attrs;
+	for (; item != NULL; item = item->next_item) {
 		if (Dflag) {
 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
 			(void) printf("Group = %d, mib_id = %d, "
@@ -3710,17 +3865,21 @@
 			    /* LINTED: (note 1) */
 			    rp = (mib2_ipRouteEntry_t *)((char *)rp +
 			    ipRouteEntrySize)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = ire_report_item_v4(rp,
-				    print_hdr_once_v4);
+				    print_hdr_once_v4, aptr);
 			}
+			if (v4a != NULL)
+				v4a -= item->length / ipRouteEntrySize;
 			print_hdr_once_v4 = B_TRUE;
 			for (rp = (mib2_ipRouteEntry_t *)item->valp;
 			    (char *)rp < (char *)item->valp + item->length;
 			    /* LINTED: (note 1) */
 			    rp = (mib2_ipRouteEntry_t *)((char *)rp +
 			    ipRouteEntrySize)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = ire_report_item_v4src(rp,
-				    print_hdr_once_v4);
+				    print_hdr_once_v4, aptr);
 			}
 		} else {
 			for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
@@ -3728,12 +3887,20 @@
 			    /* LINTED: (note 1) */
 			    rp6 = (mib2_ipv6RouteEntry_t *)((char *)rp6 +
 			    ipv6RouteEntrySize)) {
+				aptr = v6a == NULL ? NULL : *v6a++;
 				print_hdr_once_v6 = ire_report_item_v6(rp6,
-				    print_hdr_once_v6);
+				    print_hdr_once_v6, aptr);
 			}
 		}
 	} /* 'for' loop 1 ends */
 	(void) fflush(stdout);
+ire_report_done:
+	if (v4_attrs != NULL)
+		free(v4_attrs);
+	if (v6_attrs != NULL)
+		free(v6_attrs);
+	if (all_attrs != NULL)
+		free(all_attrs);
 }
 
 /*
@@ -3809,7 +3976,7 @@
  * of each type matches, then display the route.
  */
 static boolean_t
-ire_filter_match_v4(mib2_ipRouteEntry_t *rp, uint_t flag_b)
+ire_filter_match_v4(const mib2_ipRouteEntry_t *rp, uint_t flag_b)
 {
 	filter_t *fp;
 	int idx;
@@ -3865,7 +4032,7 @@
  * route.
  */
 static uint_t
-form_v4_route_flags(mib2_ipRouteEntry_t *rp, char *flags)
+form_v4_route_flags(const mib2_ipRouteEntry_t *rp, char *flags)
 {
 	uint_t flag_b;
 
@@ -3910,8 +4077,23 @@
 	return (flag_b);
 }
 
+static const char ire_hdr_v4[] =
+"\n%s Table: IPv4\n";
+static const char ire_hdr_v4_compat[] =
+"\n%s Table:\n";
+static const char ire_hdr_v4_verbose[] =
+"  Destination             Mask           Gateway          Device Mxfrg "
+"Rtt   Ref Flg  Out  In/Fwd %s\n"
+"-------------------- --------------- -------------------- ------ ----- "
+"----- --- --- ----- ------ %s\n";
+
+static const char ire_hdr_v4_normal[] =
+"  Destination           Gateway           Flags  Ref   Use   Interface %s\n"
+"-------------------- -------------------- ----- ----- ------ --------- %s\n";
+
 static boolean_t
-ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first)
+ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
+    const sec_attr_list_t *attrs)
 {
 	char			dstbuf[MAXHOSTNAMELEN + 1];
 	char			maskbuf[MAXHOSTNAMELEN + 1];
@@ -3934,29 +4116,11 @@
 		return (first);
 
 	if (first) {
-		if (Vflag) {
-			(void) puts(v4compat ?
-			    "\nIRE Table:" :
-			    "\nIRE Table: IPv4");
-			(void) puts("  Destination             Mask       "
-			    "    Gateway          "
-			    "Device Mxfrg  Rtt  Ref Flg  Out  "
-			    "In/Fwd");
-			(void) puts("-------------------- --------------- "
-			    "-------------------- "
-			    "------ ----- ----- --- --- ----- "
-			    "------");
-		} else {
-			(void) puts(v4compat ?
-			    "\nRouting Table:" :
-			    "\nRouting Table: IPv4");
-			(void) puts("  Destination        "
-			    "   Gateway           Flags  Ref   Use   "
-			    "Interface");
-			(void) puts("-------------------- "
-			    "-------------------- ----- ----- ------ "
-			    "---------");
-		}
+		(void) printf(v4compat ? ire_hdr_v4_compat : ire_hdr_v4,
+		    Vflag ? "IRE" : "Routing");
+		(void) printf(Vflag ? ire_hdr_v4_verbose : ire_hdr_v4_normal,
+		    RSECflag ? "  Gateway security attributes  " : "",
+		    RSECflag ? "-------------------------------" : "");
 		first = B_FALSE;
 	}
 
@@ -3968,7 +4132,7 @@
 	}
 	if (Vflag) {
 		(void) printf("%-20s %-15s %-20s %-6s %5u%c %4u %3u "
-		    "%-4s%6u%6u\n",
+		    "%-4s%6u%6u %s\n",
 		    dstbuf,
 		    pr_mask(rp->ipRouteMask, maskbuf, sizeof (maskbuf)),
 		    pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
@@ -3979,25 +4143,43 @@
 		    rp->ipRouteInfo.re_ref,
 		    flags,
 		    rp->ipRouteInfo.re_obpkt,
-		    rp->ipRouteInfo.re_ibpkt);
+		    rp->ipRouteInfo.re_ibpkt,
+		    pr_secattr(attrs));
 	} else {
-		(void) printf("%-20s %-20s %-5s  %4u%7u  %s\n",
+		(void) printf("%-20s %-20s %-5s  %4u%7u %-9s %s\n",
 		    dstbuf,
 		    pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
 		    flags,
 		    rp->ipRouteInfo.re_ref,
 		    rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt,
 		    octetstr(&rp->ipRouteIfIndex, 'a',
-			ifname, sizeof (ifname)));
+		    ifname, sizeof (ifname)),
+		    pr_secattr(attrs));
 	}
 	return (first);
 }
 
+static const char ire_hdr_src_v4[] =
+"\n%s Table: IPv4 Source-Specific\n";
+static const char ire_hdr_src_v4_compat[] =
+"\n%s Table: Source-Specific\n";
+static const char ire_hdr_src_v4_verbose[] =
+"  Destination        In If       Source            Gateway         "
+"  Out If    Mxfrg  Rtt  Ref Flg  Out  In/Fwd %s\n"
+"------------------ ----------- ----------------- ----------------- "
+"----------- ----- ----- --- --- ----- ------ %s\n";
+static const char ire_hdr_src_v4_normal[] =
+"  Destination    In If     Source          Gateway       Flags  Use   "
+" Out If  %s\n"
+"--------------- -------- --------------- --------------- ----- ------ "
+"-------- %s\n";
+
 /*
  * Report a source-specific route.
  */
 static boolean_t
-ire_report_item_v4src(mib2_ipRouteEntry_t *rp, boolean_t first)
+ire_report_item_v4src(const mib2_ipRouteEntry_t *rp, boolean_t first,
+    const sec_attr_list_t *attrs)
 {
 	char	dstbuf[MAXHOSTNAMELEN + 1];
 	char	srcbuf[MAXHOSTNAMELEN + 1];
@@ -4025,25 +4207,12 @@
 		return (first);
 
 	if (first) {
-		if (Vflag) {
-			(void) printf("\nIRE Table: %sSource-Specific\n",
-			    v4compat ? "" : "IPv4 ");
-			(void) puts("  Destination        In If     "
-			    "  Source            Gateway         "
-			    "  Out If    Mxfrg  Rtt  Ref Flg  Out  In/Fwd");
-			(void) puts("------------------ ----------- "
-			    "----------------- ----------------- "
-			    "----------- ----- ----- --- --- ----- ------");
-		} else {
-			(void) printf("\nRouting Table: %sSource-Specific\n",
-			    v4compat ? "" : "IPv4 ");
-			(void) puts("  Destination    In If   "
-			    "  Source          Gateway       Flags  Use   "
-			    " Out If");
-			(void) puts("--------------- -------- "
-			    "--------------- --------------- ----- ------ "
-			    "--------");
-		}
+		(void) printf(v4compat ? ire_hdr_src_v4_compat :
+		    ire_hdr_src_v4, Vflag ? "IRE" : "Routing");
+		(void) printf(Vflag ? ire_hdr_src_v4_verbose :
+		    ire_hdr_src_v4_normal,
+		    RSECflag ? "  Gateway security attributes  " : "",
+		    RSECflag ? "-------------------------------" : "");
 		first = B_FALSE;
 	}
 
@@ -4065,17 +4234,18 @@
 	(void) pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf));
 	if (Vflag) {
 		(void) printf("%-18s %-11s %-17s %-17s %-11s %4u%c %5u %3u "
-		    "%-3s %5u %6u\n",
+		    "%-3s %5u %6u %s\n",
 		    dstbuf, inif, srcbuf, gwbuf,  outif,
 		    rp->ipRouteInfo.re_max_frag,
 		    rp->ipRouteInfo.re_frag_flag ? '*' : ' ',
 		    rp->ipRouteInfo.re_rtt, rp->ipRouteInfo.re_ref, flags,
-		    rp->ipRouteInfo.re_obpkt, rp->ipRouteInfo.re_ibpkt);
+		    rp->ipRouteInfo.re_obpkt, rp->ipRouteInfo.re_ibpkt,
+		    pr_secattr(attrs));
 	} else {
-		(void) printf("%-15s %-8s %-15s %-15s %-5s %6u %-8s\n", dstbuf,
-		    inif, srcbuf, gwbuf, flags,
-		    rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt,
-		    outif);
+		(void) printf("%-15s %-8s %-15s %-15s %-5s %6u %-8s %s\n",
+		    dstbuf, inif, srcbuf, gwbuf, flags,
+		    rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt, outif,
+		    pr_secattr(attrs));
 	}
 	return (first);
 }
@@ -4145,7 +4315,7 @@
  * types, then the route is selected and displayed.
  */
 static boolean_t
-ire_filter_match_v6(mib2_ipv6RouteEntry_t *rp6, uint_t flag_b)
+ire_filter_match_v6(const mib2_ipv6RouteEntry_t *rp6, uint_t flag_b)
 {
 	filter_t *fp;
 	int idx;
@@ -4201,8 +4371,22 @@
 	return (B_TRUE);
 }
 
+static const char ire_hdr_v6[] =
+"\n%s Table: IPv6\n";
+static const char ire_hdr_v6_verbose[] =
+"  Destination/Mask            Gateway                    If    PMTU   Rtt  "
+"Ref Flags  Out   In/Fwd %s\n"
+"--------------------------- --------------------------- ----- ------ ----- "
+"--- ----- ------ ------ %s\n";
+static const char ire_hdr_v6_normal[] =
+"  Destination/Mask            Gateway                   Flags Ref   Use  "
+" If   %s\n"
+"--------------------------- --------------------------- ----- --- ------ "
+"----- %s\n";
+
 static boolean_t
-ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6, boolean_t first)
+ire_report_item_v6(const mib2_ipv6RouteEntry_t *rp6, boolean_t first,
+    const sec_attr_list_t *attrs)
 {
 	char			dstbuf[MAXHOSTNAMELEN + 1];
 	char			gwbuf[MAXHOSTNAMELEN + 1];
@@ -4256,29 +4440,16 @@
 		return (first);
 
 	if (first) {
-		if (Vflag) {
-			(void) puts("\nIRE Table: IPv6");
-			(void) puts("  Destination/Mask          "
-			    "  Gateway                   "
-			    " If    PMTU   Rtt  Ref Flags  Out   In/Fwd");
-			(void) puts("--------------------------- "
-			    "--------------------------- "
-			    "----- ------ ----- --- ----- ------ ------");
-		} else {
-			(void) puts("\nRouting Table: IPv6");
-			(void) puts("  Destination/Mask          "
-			    "  Gateway                   Flags Ref   Use  "
-			    " If  ");
-			(void) puts("--------------------------- "
-			    "--------------------------- ----- --- ------ "
-			    "-----");
-		}
+		(void) printf(ire_hdr_v6, Vflag ? "IRE" : "Routing");
+		(void) printf(Vflag ? ire_hdr_v6_verbose : ire_hdr_v6_normal,
+		    RSECflag ? "  Gateway security attributes  " : "",
+		    RSECflag ? "-------------------------------" : "");
 		first = B_FALSE;
 	}
 
 	if (Vflag) {
 		(void) printf("%-27s %-27s %-5s %5u%c %5u %3u "
-		    "%-5s %6u %6u\n",
+		    "%-5s %6u %6u %s\n",
 		    pr_prefix6(&rp6->ipv6RouteDest,
 			rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
 		    IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
@@ -4292,9 +4463,10 @@
 		    rp6->ipv6RouteInfo.re_ref,
 		    flags,
 		    rp6->ipv6RouteInfo.re_obpkt,
-		    rp6->ipv6RouteInfo.re_ibpkt);
+		    rp6->ipv6RouteInfo.re_ibpkt,
+		    pr_secattr(attrs));
 	} else {
-		(void) printf("%-27s %-27s %-5s %3u %6u %-5s\n",
+		(void) printf("%-27s %-27s %-5s %3u %6u %-5s %s\n",
 		    pr_prefix6(&rp6->ipv6RouteDest,
 			rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
 		    IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
@@ -4304,11 +4476,59 @@
 		    rp6->ipv6RouteInfo.re_ref,
 		    rp6->ipv6RouteInfo.re_obpkt + rp6->ipv6RouteInfo.re_ibpkt,
 		    octetstr(&rp6->ipv6RouteIfIndex, 'a',
-		    ifname, sizeof (ifname)));
+		    ifname, sizeof (ifname)),
+		    pr_secattr(attrs));
 	}
 	return (first);
 }
 
+/*
+ * Common attribute-gathering routine for all transports.
+ */
+static mib2_transportMLPEntry_t **
+gather_attrs(const mib_item_t *item, int group, int mib_id, int esize)
+{
+	int transport_count = 0;
+	const mib_item_t *iptr;
+	mib2_transportMLPEntry_t **attrs, *tme;
+
+	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
+		if (iptr->group == group && iptr->mib_id == mib_id)
+			transport_count += iptr->length / esize;
+	}
+	if (transport_count <= 0)
+		return (NULL);
+	attrs = calloc(transport_count, sizeof (*attrs));
+	if (attrs == NULL) {
+		perror("gather_attrs calloc failed");
+		return (NULL);
+	}
+	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
+		if (iptr->group == group && iptr->mib_id == EXPER_XPORT_MLP) {
+			for (tme = iptr->valp;
+			    (char *)tme < (char *)iptr->valp + iptr->length;
+			    /* LINTED: (note 1) */
+			    tme = (mib2_transportMLPEntry_t *)((char *)tme +
+			    transportMLPSize)) {
+				attrs[tme->tme_connidx] = tme;
+			}
+		}
+	}
+	return (attrs);
+}
+
+static void
+print_transport_label(const mib2_transportMLPEntry_t *attr)
+{
+	if (!RSECflag || attr == NULL)
+		return;
+
+	if (bisinvalid(&attr->tme_label))
+		(void) printf("   INVALID\n");
+	else
+		(void) printf("   %s\n", sl_to_str(&attr->tme_label));
+}
+
 /* ------------------------------ TCP_REPORT------------------------------- */
 
 static const char tcp_hdr_v4[] =
@@ -4317,43 +4537,65 @@
 "\nTCP\n";
 static const char tcp_hdr_v4_verbose[] =
 "Local/Remote Address Swind  Snext     Suna   Rwind  Rnext     Rack   "
-" Rto   Mss  State\n"
+" Rto   Mss     State\n"
 "-------------------- ----- -------- -------- ----- -------- -------- "
-"----- ----- -----\n";
+"----- ----- -----------\n";
 static const char tcp_hdr_v4_normal[] =
-"   Local Address        Remote Address    Swind Send-Q Rwind Recv-Q  State\n"
-"-------------------- -------------------- ----- ------ ----- ------ -------\n";
+"   Local Address        Remote Address    Swind Send-Q Rwind Recv-Q "
+"   State\n"
+"-------------------- -------------------- ----- ------ ----- ------ "
+"-----------\n";
 
 static const char tcp_hdr_v6[] =
 "\nTCP: IPv6\n";
 static const char tcp_hdr_v6_verbose[] =
 "Local/Remote Address              Swind  Snext     Suna   Rwind  Rnext   "
-"  Rack    Rto   Mss    State      If  \n"
+"  Rack    Rto   Mss    State      If\n"
 "--------------------------------- ----- -------- -------- ----- -------- "
 "-------- ----- ----- ----------- -----\n";
 static const char tcp_hdr_v6_normal[] =
 "   Local Address                     Remote Address                 "
-"Swind Send-Q Rwind Recv-Q   State      If \n"
+"Swind Send-Q Rwind Recv-Q   State      If\n"
 "--------------------------------- --------------------------------- "
 "----- ------ ----- ------ ----------- -----\n";
 
-static boolean_t tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first);
-static boolean_t tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first);
+static boolean_t tcp_report_item_v4(const mib2_tcpConnEntry_t *,
+    boolean_t first, const mib2_transportMLPEntry_t *);
+static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
+    boolean_t first, const mib2_transportMLPEntry_t *);
 
 static void
-tcp_report(mib_item_t *item)
+tcp_report(const mib_item_t *item)
 {
 	int			jtemp = 0;
 	boolean_t		print_hdr_once_v4 = B_TRUE;
 	boolean_t		print_hdr_once_v6 = B_TRUE;
 	mib2_tcpConnEntry_t	*tp;
 	mib2_tcp6ConnEntry_t	*tp6;
+	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
+	mib2_transportMLPEntry_t **v4a, **v6a;
+	mib2_transportMLPEntry_t *aptr;
 
 	if (!protocol_selected(IPPROTO_TCP))
 		return;
 
+	/*
+	 * Preparation pass: the kernel returns separate entries for TCP
+	 * connection table entries and Multilevel Port attributes.  We loop
+	 * through the attributes first and set up an array for each address
+	 * family.
+	 */
+	v4_attrs = family_selected(AF_INET) && RSECflag ?
+	    gather_attrs(item, MIB2_TCP, MIB2_TCP_CONN, tcpConnEntrySize) :
+	    NULL;
+	v6_attrs = family_selected(AF_INET6) && RSECflag ?
+	    gather_attrs(item, MIB2_TCP6, MIB2_TCP6_CONN, tcp6ConnEntrySize) :
+	    NULL;
+
 	/* 'for' loop 1: */
-	for (; item; item = item->next_item) {
+	v4a = v4_attrs;
+	v6a = v6_attrs;
+	for (; item != NULL; item = item->next_item) {
 		if (Dflag) {
 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
 			(void) printf("Group = %d, mib_id = %d, "
@@ -4379,8 +4621,9 @@
 			    /* LINTED: (note 1) */
 			    tp = (mib2_tcpConnEntry_t *)((char *)tp +
 			    tcpConnEntrySize)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = tcp_report_item_v4(tp,
-				    print_hdr_once_v4);
+				    print_hdr_once_v4, aptr);
 			}
 		} else {
 			for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
@@ -4388,16 +4631,23 @@
 			    /* LINTED: (note 1) */
 			    tp6 = (mib2_tcp6ConnEntry_t *)((char *)tp6 +
 			    tcp6ConnEntrySize)) {
+				aptr = v6a == NULL ? NULL : *v6a++;
 				print_hdr_once_v6 = tcp_report_item_v6(tp6,
-				    print_hdr_once_v6);
+				    print_hdr_once_v6, aptr);
 			}
 		}
 	} /* 'for' loop 1 ends */
 	(void) fflush(stdout);
+
+	if (v4_attrs != NULL)
+		free(v4_attrs);
+	if (v6_attrs != NULL)
+		free(v6_attrs);
 }
 
 static boolean_t
-tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first)
+tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, boolean_t first,
+    const mib2_transportMLPEntry_t *attr)
 {
 	/*
 	 * lname and fname below are for the hostname as well as the portname
@@ -4411,10 +4661,8 @@
 		return (first); /* Nothing to print */
 
 	if (first) {
-		(void) fputs(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4, stdout);
-		(void) fputs(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal,
-		    stdout);
-		first = B_FALSE;
+		(void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
+		(void) printf(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal);
 	}
 
 	if (Vflag) {
@@ -4432,7 +4680,7 @@
 		    tp->tcpConnEntryInfo.ce_rack,
 		    tp->tcpConnEntryInfo.ce_rto,
 		    tp->tcpConnEntryInfo.ce_mss,
-		    mitcp_state(tp->tcpConnEntryInfo.ce_state));
+		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
 	} else {
 		int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
 		    (int)tp->tcpConnEntryInfo.ce_suna - 1;
@@ -4448,13 +4696,17 @@
 		    (sq >= 0) ? sq : 0,
 		    tp->tcpConnEntryInfo.ce_rwnd,
 		    (rq >= 0) ? rq : 0,
-		    mitcp_state(tp->tcpConnEntryInfo.ce_state));
+		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
 	}
-	return (first);
+
+	print_transport_label(attr);
+
+	return (B_FALSE);
 }
 
 static boolean_t
-tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first)
+tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, boolean_t first,
+    const mib2_transportMLPEntry_t *attr)
 {
 	/*
 	 * lname and fname below are for the hostname as well as the portname
@@ -4470,18 +4722,18 @@
 		return (first); /* Nothing to print */
 
 	if (first) {
-		(void) fputs(tcp_hdr_v6, stdout);
-		(void) fputs(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal,
-		    stdout);
-		first = B_FALSE;
+		(void) printf(tcp_hdr_v6);
+		(void) printf(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal);
 	}
 
 	ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
 	    if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
+	if (ifnamep == NULL)
+		ifnamep = "";
 
 	if (Vflag) {
 		(void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
-		    "%5u %5u %-11s %-5s\n",
+		    "%5u %5u %-11s %s\n",
 		    pr_ap6(&tp6->tcp6ConnLocalAddress,
 			tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
 		    pr_ap6(&tp6->tcp6ConnRemAddress,
@@ -4494,15 +4746,15 @@
 		    tp6->tcp6ConnEntryInfo.ce_rack,
 		    tp6->tcp6ConnEntryInfo.ce_rto,
 		    tp6->tcp6ConnEntryInfo.ce_mss,
-		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state),
-		    (ifnamep == NULL) ? "" : ifnamep);
+		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
+		    ifnamep);
 	} else {
 		int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
 		    (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
 		int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
 		    (int)tp6->tcp6ConnEntryInfo.ce_rack;
 
-		(void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %-5s\n",
+		(void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
 		    pr_ap6(&tp6->tcp6ConnLocalAddress,
 			tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
 		    pr_ap6(&tp6->tcp6ConnRemAddress,
@@ -4511,35 +4763,61 @@
 		    (sq >= 0) ? sq : 0,
 		    tp6->tcp6ConnEntryInfo.ce_rwnd,
 		    (rq >= 0) ? rq : 0,
-		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state),
-		    (ifnamep == NULL) ? "" : ifnamep);
+		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
+		    ifnamep);
 	}
-	return (first);
+
+	print_transport_label(attr);
+
+	return (B_FALSE);
 }
 
 /* ------------------------------- UDP_REPORT------------------------------- */
 
-static boolean_t udp_report_item_v4(mib2_udpEntry_t *ude, boolean_t first);
-static boolean_t udp_report_item_v6(mib2_udp6Entry_t *ude6, boolean_t first);
-
-static char *udp_hdr_v6 =
+static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
+    boolean_t first, const mib2_transportMLPEntry_t *attr);
+static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
+    boolean_t first, const mib2_transportMLPEntry_t *attr);
+
+static const char udp_hdr_v4[] =
+"   Local Address        Remote Address      State\n"
+"-------------------- -------------------- ----------\n";
+
+static const char udp_hdr_v6[] =
 "   Local Address                     Remote Address                 "
-"  State      If  \n"
+"  State      If\n"
 "--------------------------------- --------------------------------- "
 "---------- -----\n";
 
 static void
-udp_report(mib_item_t *item)
+udp_report(const mib_item_t *item)
 {
 	int			jtemp = 0;
 	boolean_t		print_hdr_once_v4 = B_TRUE;
 	boolean_t		print_hdr_once_v6 = B_TRUE;
 	mib2_udpEntry_t		*ude;
 	mib2_udp6Entry_t	*ude6;
+	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
+	mib2_transportMLPEntry_t **v4a, **v6a;
+	mib2_transportMLPEntry_t *aptr;
 
 	if (!protocol_selected(IPPROTO_UDP))
 		return;
 
+	/*
+	 * Preparation pass: the kernel returns separate entries for UDP
+	 * connection table entries and Multilevel Port attributes.  We loop
+	 * through the attributes first and set up an array for each address
+	 * family.
+	 */
+	v4_attrs = family_selected(AF_INET) && RSECflag ?
+	    gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
+	v6_attrs = family_selected(AF_INET6) && RSECflag ?
+	    gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
+	    NULL;
+
+	v4a = v4_attrs;
+	v6a = v6_attrs;
 	/* 'for' loop 1: */
 	for (; item; item = item->next_item) {
 		if (Dflag) {
@@ -4567,8 +4845,9 @@
 			    /* LINTED: (note 1) */
 			    ude = (mib2_udpEntry_t *)((char *)ude +
 			    udpEntrySize)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = udp_report_item_v4(ude,
-				    print_hdr_once_v4);
+				    print_hdr_once_v4, aptr);
 			}
 		} else {
 			for (ude6 = (mib2_udp6Entry_t *)item->valp;
@@ -4576,109 +4855,91 @@
 			    /* LINTED: (note 1) */
 			    ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
 			    udp6EntrySize)) {
+				aptr = v6a == NULL ? NULL : *v6a++;
 				print_hdr_once_v6 = udp_report_item_v6(ude6,
-				    print_hdr_once_v6);
+				    print_hdr_once_v6, aptr);
 			}
 		}
 	} /* 'for' loop 1 ends */
 	(void) fflush(stdout);
+
+	if (v4_attrs != NULL)
+		free(v4_attrs);
+	if (v6_attrs != NULL)
+		free(v6_attrs);
 }
 
 static boolean_t
-udp_report_item_v4(mib2_udpEntry_t *ude, boolean_t first)
+udp_report_item_v4(const mib2_udpEntry_t *ude, boolean_t first,
+    const mib2_transportMLPEntry_t *attr)
 {
 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 			/* hostname + portname */
-	char	*cp;
 
 	if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
 		return (first); /* Nothing to print */
 
 	if (first) {
-		(void) puts(v4compat ? "\nUDP" : "\nUDP: IPv4");
-		(void) puts(
-		    "   Local Address         Remote Address     State");
-		(void) puts(
-		    "-------------------- -------------------- -------");
+		(void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
+		(void) printf(udp_hdr_v4);
 		first = B_FALSE;
 	}
 
-	switch (ude->udpEntryInfo.ue_state) {
-	case MIB2_UDP_unbound:
-		cp = "Unbound";
-		break;
-	case MIB2_UDP_idle:
-		cp = "Idle";
-		break;
-	case MIB2_UDP_connected:
-		cp = "Connected";
-		break;
-	default:
-		cp = "Unknown";
-		break;
-	}
 	(void) printf("%-20s ",
 	    pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
 	    lname, sizeof (lname)));
-	if (ude->udpEntryInfo.ue_state == MIB2_UDP_connected) {
-		(void) printf("%-20s ",
-		    pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
-		    ude->udpEntryInfo.ue_RemotePort, "udp",
-		    lname, sizeof (lname)));
-	} else {
-		(void) printf("%-20s ", "");
-	}
-	(void) printf("  %s\n", cp);
+	(void) printf("%-20s %s\n",
+	    ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
+	    pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
+	    ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
+	    "",
+	    miudp_state(ude->udpEntryInfo.ue_state, attr));
+
+	/*
+	 * UDP sockets don't have remote attributes, so there's no need to
+	 * print them here.
+	 */
+
 	return (first);
 }
 
 static boolean_t
-udp_report_item_v6(mib2_udp6Entry_t *ude6, boolean_t first)
+udp_report_item_v6(const mib2_udp6Entry_t *ude6, boolean_t first,
+    const mib2_transportMLPEntry_t *attr)
 {
 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 			/* hostname + portname */
-	char	*cp;
 	char	ifname[LIFNAMSIZ + 1];
+	const char *ifnamep;
 
 	if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
 		return (first); /* Nothing to print */
 
 	if (first) {
-		(void) printf("\nUDP: IPv6\n%s", udp_hdr_v6);
+		(void) printf("\nUDP: IPv6\n");
+		(void) printf(udp_hdr_v6);
 		first = B_FALSE;
 	}
 
-	switch (ude6->udp6EntryInfo.ue_state) {
-	case MIB2_UDP_unbound:
-		cp = "Unbound";
-		break;
-	case MIB2_UDP_idle:
-		cp = "Idle";
-		break;
-	case MIB2_UDP_connected:
-		cp = "Connected";
-		break;
-	default:
-		cp = "Unknown";
-		break;
-	}
+	ifnamep = (ude6->udp6IfIndex != 0) ?
+	    if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
+
 	(void) printf("%-33s ",
 	    pr_ap6(&ude6->udp6LocalAddress,
 	    ude6->udp6LocalPort, "udp", lname, sizeof (lname)));
-	if (ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected) {
-		(void) printf("%-33s ",
-		    pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
-		    ude6->udp6EntryInfo.ue_RemotePort, "udp",
-		    lname, sizeof (lname)));
-	} else {
-		(void) printf("%-33s ", "");
-	}
-	if (ude6->udp6IfIndex != 0 &&
-	    (if_indextoname(ude6->udp6IfIndex, ifname) != NULL)) {
-		(void) printf("%-10s %-5s\n", cp, ifname);
-	} else {
-		(void) printf("%-10s\n", cp);
-	}
+	(void) printf("%-33s %-10s %s\n",
+	    ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
+	    pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
+	    ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
+	    "",
+	    miudp_state(ude6->udp6EntryInfo.ue_state, attr),
+	    ifnamep == NULL ? "" : ifnamep);
+
+	/*
+	 * UDP sockets don't have remote attributes, so there's no need to
+	 * print them here.
+	 */
+
 	return (first);
 }
 
@@ -4693,38 +4954,66 @@
 "------ ------ ------ ------ ------- -----------";
 
 static const char *
-nssctp_state(int state)
+nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
 {
+	static char sctpsbuf[50];
+	const char *cp;
+
 	switch (state) {
 	case MIB2_SCTP_closed:
-		return ("CLOSED");
+		cp = "CLOSED";
+		break;
 	case MIB2_SCTP_cookieWait:
-		return ("COOKIE_WAIT");
+		cp = "COOKIE_WAIT";
+		break;
 	case MIB2_SCTP_cookieEchoed:
-		return ("COOKIE_ECHOED");
+		cp = "COOKIE_ECHOED";
+		break;
 	case MIB2_SCTP_established:
-		return ("ESTABLISHED");
+		cp = "ESTABLISHED";
+		break;
 	case MIB2_SCTP_shutdownPending:
-		return ("SHUTDOWN_PENDING");
+		cp = "SHUTDOWN_PENDING";
+		break;
 	case MIB2_SCTP_shutdownSent:
-		return ("SHUTDOWN_SENT");
+		cp = "SHUTDOWN_SENT";
+		break;
 	case MIB2_SCTP_shutdownReceived:
-		return ("SHUTDOWN_RECEIVED");
+		cp = "SHUTDOWN_RECEIVED";
+		break;
 	case MIB2_SCTP_shutdownAckSent:
-		return ("SHUTDOWN_ACK_SENT");
+		cp = "SHUTDOWN_ACK_SENT";
+		break;
 	case MIB2_SCTP_listen:
-		return ("LISTEN");
+		cp = "LISTEN";
+		break;
 	default:
-		return ("UNKNOWN STATE");
+		(void) snprintf(sctpsbuf, sizeof (sctpsbuf),
+		    "UNKNOWN STATE(%d)", state);
+		cp = sctpsbuf;
+		break;
 	}
+
+	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
+		if (cp != sctpsbuf) {
+			(void) strlcpy(sctpsbuf, cp, sizeof (sctpsbuf));
+			cp = sctpsbuf;
+		}
+		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
+			(void) strlcat(sctpsbuf, " P", sizeof (sctpsbuf));
+		if (attr->tme_flags & MIB2_TMEF_SHARED)
+			(void) strlcat(sctpsbuf, " S", sizeof (sctpsbuf));
+	}
+
+	return (cp);
 }
 
-static mib2_sctpConnRemoteEntry_t *
-sctp_getnext_rem(mib_item_t **itemp, mib2_sctpConnRemoteEntry_t *current,
-    uint32_t associd)
+static const mib2_sctpConnRemoteEntry_t *
+sctp_getnext_rem(const mib_item_t **itemp,
+    const mib2_sctpConnRemoteEntry_t *current, uint32_t associd)
 {
-	mib_item_t *item = *itemp;
-	mib2_sctpConnRemoteEntry_t	*sre;
+	const mib_item_t *item = *itemp;
+	const mib2_sctpConnRemoteEntry_t	*sre;
 
 	for (; item != NULL; item = item->next_item, current = NULL) {
 		if (!(item->group == MIB2_SCTP &&
@@ -4734,15 +5023,15 @@
 
 		if (current != NULL) {
 			/* LINTED: (note 1) */
-			sre = (mib2_sctpConnRemoteEntry_t *)((char *)current +
-			    sctpRemoteEntrySize);
+			sre = (const mib2_sctpConnRemoteEntry_t *)
+			    ((const char *)current + sctpRemoteEntrySize);
 		} else {
 			sre = item->valp;
 		}
 		for (; (char *)sre < (char *)item->valp + item->length;
-			/* LINTED: (note 1) */
-			sre = (mib2_sctpConnRemoteEntry_t *)((char *)sre +
-			    sctpRemoteEntrySize)) {
+		    /* LINTED: (note 1) */
+		    sre = (const mib2_sctpConnRemoteEntry_t *)
+		    ((const char *)sre + sctpRemoteEntrySize)) {
 			if (sre->sctpAssocId != associd) {
 				continue;
 			}
@@ -4754,12 +5043,12 @@
 	return (NULL);
 }
 
-static mib2_sctpConnLocalEntry_t *
-sctp_getnext_local(mib_item_t **itemp, mib2_sctpConnLocalEntry_t *current,
-    uint32_t associd)
+static const mib2_sctpConnLocalEntry_t *
+sctp_getnext_local(const mib_item_t **itemp,
+    const mib2_sctpConnLocalEntry_t *current, uint32_t associd)
 {
-	mib_item_t *item = *itemp;
-	mib2_sctpConnLocalEntry_t	*sle;
+	const mib_item_t *item = *itemp;
+	const mib2_sctpConnLocalEntry_t	*sle;
 
 	for (; item != NULL; item = item->next_item, current = NULL) {
 		if (!(item->group == MIB2_SCTP &&
@@ -4769,15 +5058,15 @@
 
 		if (current != NULL) {
 			/* LINTED: (note 1) */
-			sle = (mib2_sctpConnLocalEntry_t *)((char *)current +
-			    sctpLocalEntrySize);
+			sle = (const mib2_sctpConnLocalEntry_t *)
+			    ((const char *)current + sctpLocalEntrySize);
 		} else {
 			sle = item->valp;
 		}
 		for (; (char *)sle < (char *)item->valp + item->length;
-			/* LINTED: (note 1) */
-			sle = (mib2_sctpConnLocalEntry_t *)((char *)sle +
-			    sctpLocalEntrySize)) {
+		    /* LINTED: (note 1) */
+		    sle = (const mib2_sctpConnLocalEntry_t *)
+		    ((const char *)sle + sctpLocalEntrySize)) {
 			if (sle->sctpAssocId != associd) {
 				continue;
 			}
@@ -4830,14 +5119,15 @@
 }
 
 static void
-sctp_conn_report_item(mib_item_t *head, mib2_sctpConnEntry_t *sp)
+sctp_conn_report_item(const mib_item_t *head, const mib2_sctpConnEntry_t *sp,
+    const mib2_transportMLPEntry_t *attr)
 {
 	char		lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 	char		fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
-	mib2_sctpConnRemoteEntry_t	*sre = NULL;
-	mib2_sctpConnLocalEntry_t	*sle = NULL;
-	mib_item_t	*local = head;
-	mib_item_t	*remote = head;
+	const mib2_sctpConnRemoteEntry_t	*sre = NULL;
+	const mib2_sctpConnLocalEntry_t	*sle = NULL;
+	const mib_item_t *local = head;
+	const mib_item_t *remote = head;
 	uint32_t	id = sp->sctpAssocId;
 	boolean_t	printfirst = B_TRUE;
 
@@ -4853,7 +5143,9 @@
 	    sp->sctpConnEntryInfo.ce_rwnd,
 	    sp->sctpConnEntryInfo.ce_recvq,
 	    sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
-	    nssctp_state(sp->sctpAssocState));
+	    nssctp_state(sp->sctpAssocState, attr));
+
+	print_transport_label(attr);
 
 	if (!Vflag) {
 		return;
@@ -4902,12 +5194,25 @@
 }
 
 static void
-sctp_report(mib_item_t *item)
+sctp_report(const mib_item_t *item)
 {
-	mib_item_t		*head;
-	mib2_sctpConnEntry_t	*sp;
+	const mib_item_t		*head;
+	const mib2_sctpConnEntry_t	*sp;
 	boolean_t		first = B_TRUE;
-
+	mib2_transportMLPEntry_t **attrs, **aptr;
+	mib2_transportMLPEntry_t *attr;
+
+	/*
+	 * Preparation pass: the kernel returns separate entries for SCTP
+	 * connection table entries and Multilevel Port attributes.  We loop
+	 * through the attributes first and set up an array for each address
+	 * family.
+	 */
+	attrs = RSECflag ?
+	    gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
+	    NULL;
+
+	aptr = attrs;
 	head = item;
 	for (; item != NULL; item = item->next_item) {
 
@@ -4916,11 +5221,10 @@
 			continue;
 
 		for (sp = item->valp;
-			(char *)sp < (char *)item->valp + item->length;
-			/* LINTED: (note 1) */
-			sp = (mib2_sctpConnEntry_t *)((char *)sp +
-			    sctpEntrySize)) {
-
+		    (char *)sp < (char *)item->valp + item->length;
+		    /* LINTED: (note 1) */
+		    sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
+			attr = aptr == NULL ? NULL : *aptr++;
 			if (Aflag ||
 			    sp->sctpAssocState >= MIB2_SCTP_established) {
 				if (first == B_TRUE) {
@@ -4928,10 +5232,12 @@
 					(void) puts(sctp_hdr_normal);
 					first = B_FALSE;
 				}
-				sctp_conn_report_item(head, sp);
+				sctp_conn_report_item(head, sp, attr);
 			}
 		}
 	}
+	if (attrs != NULL)
+		free(attrs);
 }
 
 static char *
@@ -5330,7 +5636,8 @@
  * Does not print /128 to save space in printout. H flag carries this notion.
  */
 static char *
-pr_prefix6(struct in6_addr *addr, uint_t prefixlen, char *dst, uint_t dstlen)
+pr_prefix6(const struct in6_addr *addr, uint_t prefixlen, char *dst,
+    uint_t dstlen)
 {
 	char *cp;
 
@@ -5634,6 +5941,53 @@
 	}
 }
 
+#define	MAX_STRING_SIZE	256
+
+static const char *
+pr_secattr(const sec_attr_list_t *attrs)
+{
+	int i;
+	char buf[MAX_STRING_SIZE + 1], *cp;
+	static char *sbuf;
+	static size_t sbuf_len;
+	struct rtsa_s rtsa;
+	const sec_attr_list_t *aptr;
+
+	if (!RSECflag || attrs == NULL)
+		return ("");
+
+	for (aptr = attrs, i = 1; aptr != NULL; aptr = aptr->sal_next)
+		i += MAX_STRING_SIZE;
+	if (i > sbuf_len) {
+		cp = realloc(sbuf, i);
+		if (cp == NULL) {
+			perror("realloc security attribute buffer");
+			return ("");
+		}
+		sbuf_len = i;
+		sbuf = cp;
+	}
+
+	cp = sbuf;
+	while (attrs != NULL) {
+		const mib2_ipAttributeEntry_t *iae = attrs->sal_attr;
+
+		/* note: effectively hard-coded in rtsa_keyword */
+		rtsa.rtsa_mask = RTSA_CIPSO | RTSA_SLRANGE | RTSA_DOI;
+		rtsa.rtsa_slrange = iae->iae_slrange;
+		rtsa.rtsa_doi = iae->iae_doi;
+
+		(void) snprintf(cp, MAX_STRING_SIZE,
+		    "<%s>%s ", rtsa_to_str(&rtsa, buf, sizeof (buf)),
+		    attrs->sal_next == NULL ? "" : ",");
+		cp += strlen(cp);
+		attrs = attrs->sal_next;
+	}
+	*cp = '\0';
+
+	return (sbuf);
+}
+
 /*
  * Pretty print a port number. If the Nflag was
  * specified, use numbers instead of names.
@@ -5936,7 +6290,8 @@
  */
 /*PRINTFLIKE2*/
 static void
-fatal(int errcode, char *format, ...) {
+fatal(int errcode, char *format, ...)
+{
 	va_list argp;
 
 	if (format == NULL)
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -58,6 +59,7 @@
 CMDPROG=	in.telnetd
 IPSECUTILPROG=	ikeadm ipsecalgs ipsecconf ipseckey
 K5PROGS=	in.telnetd in.rlogind in.rshd
+TSNETPROG=	route
 DEFAULTFILES=	telnetd.dfl
 
 PROGSRCS=	$(PROG:%=%.c)
@@ -148,6 +150,7 @@
 				-I$(SRC)/lib/pam_modules/krb5
 LDLIBS +=	$(K5LIBS)
 $(IPSECUTILPROG)	:=	LDLIBS += -lipsecutil
+$(TSNETPROG)		:=	LDLIBS += -ltsnet
 
 in.rarpd		:=	LDLIBS += -linetutil
 route			:=	CPPFLAGS += -DNDEBUG
@@ -246,7 +249,7 @@
 	$(LINT.c) ipsecconf.c $(LDLIBS) -lsocket -lnsl -lipsecutil
 	$(LINT.c) ipseckey.c $(LDLIBS) -lsocket -lnsl -lipsecutil
 	$(LINT.c) ikeadm.c $(LDLIBS) -lnsl -lipsecutil
-	$(LINT.c) route.c $(LDLIBS) -lsocket -lnsl
+	$(LINT.c) route.c $(LDLIBS) -lsocket -lnsl -ltsnet
 	$(LINT.c) routeadm.c $(LDLIBS) -lsocket
 	$(LINT.c) syncinit.c $(LDLIBS) -ldlpi
 	$(LINT.c) syncloop.c $(LDLIBS) -ldlpi
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -162,6 +162,7 @@
 static int	clr_tun_encap_limit(char *arg, int64_t param);
 static int	set_tun_hop_limit(char *arg, int64_t param);
 static int	setzone(char *arg, int64_t param);
+static int	setallzones(char *arg, int64_t param);
 static int	setifsrc(char *arg, int64_t param);
 
 #ifdef DEBUG
@@ -307,6 +308,7 @@
 	{ "destination", NEXTARG,	setifdstaddr,	0,	AF_ANY },
 	{ "zone",	NEXTARG,	setzone,	0,	AF_ANY },
 	{ "-zone",	0,		setzone,	0,	AF_ANY },
+	{ "all-zones",	0,		setallzones,	0,	AF_ANY },
 	{ "ether",	OPTARG,		setifether,	0,	AF_ANY },
 	{ "usesrc",	NEXTARG,	setifsrc,	0,	AF_ANY },
 	{ 0,		0,		setifaddr,	0,	AF_ANY },
@@ -2858,6 +2860,18 @@
 	return (0);
 }
 
+/* Put interface into all zones */
+/* ARGSUSED */
+static int
+setallzones(char *arg, int64_t param)
+{
+	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
+	lifr.lifr_zoneid = ALL_ZONES;
+	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
+		Perror0_exit("SIOCSLIFZONE");
+	return (0);
+}
+
 /* Set source address to use */
 /* ARGSUSED */
 static int
@@ -2958,7 +2972,9 @@
 		    lifr.lifr_zoneid != getzoneid()) {
 			char zone_name[ZONENAME_MAX];
 
-			if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
+			if (lifr.lifr_zoneid == ALL_ZONES) {
+				(void) printf("\n\tall-zones");
+			} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
 			    sizeof (zone_name)) < 0) {
 				(void) printf("\n\tzone %d", lifr.lifr_zoneid);
 			} else {
@@ -4765,7 +4781,8 @@
 	    "\t[ standby | -standby ]\n"
 	    "\t[ failover | -failover ]\n"
 	    "\t[ zone <zonename> | -zone ]\n"
-	    "\t[ usesrc <interface> ]\n");
+	    "\t[ usesrc <interface> ]\n"
+	    "\t[ all-zones ]\n");
 
 	(void) fprintf(stderr, "or\n");
 	(void) fprintf(stderr,
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Copyright (c) 1983, 1988, 1993
@@ -1692,6 +1692,8 @@
  * ss is a pointer to the beginning of the data following the
  * rt_msghdr contained in the routing socket message, which consists
  * of a string of concatenated sockaddr structure of different types.
+ *
+ * Extended attributes can be appended at the end of the list.
  */
 static int
 rt_xaddrs(struct rt_addrinfo *info,
@@ -1766,11 +1768,35 @@
 			goto xaddr_done;
 		}
 	}
+
+	while (((char *)ss + sizeof (rtm_ext_t)) <= lim) {
+		rtm_ext_t *tp;
+		char *nxt;
+
+		/* LINTED: alignment */
+		tp = (rtm_ext_t *)ss;
+		nxt = (char *)(tp + 1) + tp->rtmex_len;
+
+		if (!IS_P2ALIGNED(tp->rtmex_len, sizeof (uint32_t)) ||
+		    nxt > lim) {
+			break;
+		}
+
+		/* LINTED: alignment */
+		ss = (struct sockaddr_storage *)nxt;
+	}
+
 	if ((char *)ss != lim) {
-		if (!(prev_complaints & XBAD_LONG))
+		if ((char *)ss > lim) {
+			if (!(prev_complaints & XBAD_SHORT))
+				msglog("routing message too short by %d bytes",
+				    (char *)ss - lim);
+			complaints |= XBAD_SHORT;
+		} else if (!(prev_complaints & XBAD_LONG)) {
 			msglog("%d bytes of routing message left over",
 			    lim - (char *)ss);
-		complaints |= XBAD_LONG;
+			complaints |= XBAD_LONG;
+		}
 		retv = -1;
 	}
 xaddr_done:
--- a/usr/src/cmd/cmd-inet/usr.sbin/route.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c	Fri Mar 24 12:29:20 2006 -0800
@@ -74,11 +74,16 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <stropts.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <assert.h>
+#include <strings.h>
+
+#include <libtsnet.h>
+#include <tsol/label.h>
 
 static struct keytab {
 	char	*kt_cp;
@@ -168,6 +173,8 @@
 	{"setsrc",	K_SETSRC},
 #define	K_SHOW		43
 	{"show",	K_SHOW},
+#define	K_SECATTR	43
+	{"secattr",	K_SECATTR},
 	{0, 0}
 };
 
@@ -206,14 +213,16 @@
 	su_t ri_ifa;
 	su_t ri_ifp;
 	char *ri_ifp_str;
+	int ri_rtsa_cnt;	/* number of gateway security attributes */
+	struct rtsa_s ri_rtsa;	/* enough space for one attribute */
 } rtcmd_irep_t;
 
 typedef struct	mib_item_s {
-	struct mib_item_s	*next_item;
-	long			group;
-	long			mib_id;
-	long			length;
-	intmax_t		*valp;
+	struct mib_item_s *next_item;
+	long group;
+	long mib_id;
+	long length;
+	intmax_t *valp;
 } mib_item_t;
 
 typedef enum {
@@ -257,18 +266,18 @@
 static char		*netname(struct sockaddr *sa);
 static int		newroute(char **argv);
 static rtcmd_irep_t	*new_rtcmd_irep(void);
-static void		pmsg_addrs(char *cp, int addrs);
-static void		pmsg_common(struct rt_msghdr *rtm);
+static void		pmsg_addrs(const char *cp, size_t len, uint_t addrs);
+static void		pmsg_common(const struct rt_msghdr *rtm, size_t len);
 static void		print_getmsg(rtcmd_irep_t *req_rt,
     struct rt_msghdr *rtm, int msglen);
 static void		print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip,
     boolean_t gw_good, boolean_t to_saved);
 static void		print_rtmsg(struct rt_msghdr *rtm, int msglen);
 static void		quit(char *s, int err) __NORETURN;
-static char		*routename(struct sockaddr *sa);
+static char		*routename(const struct sockaddr *sa);
 static void		rtmonitor(int argc, char *argv[]);
 static int		rtmsg(rtcmd_irep_t *rcip);
-static int		salen(struct sockaddr *sa);
+static int		salen(const struct sockaddr *sa);
 static void		save_route(int argc, char **argv, int do_flush);
 static void		save_string(char **dst, char *src);
 static int		search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt,
@@ -283,6 +292,7 @@
 static void		syntax_error(char *err, ...);
 static void		usage(char *cp);
 static void		write_to_rtfile(FILE *fp, int argc, char **argv);
+static void		pmsg_secattr(const char *, size_t, const char *);
 
 static pid_t		pid;
 static int		s;
@@ -315,7 +325,7 @@
 
 static struct {
 	struct	rt_msghdr m_rtm;
-	char	m_space[512];
+	char	m_space[BUF_SIZE];
 } m_rtmsg;
 
 /*
@@ -337,7 +347,6 @@
 #define	BAD_ADDR	-1	/* prefix is invalid */
 #define	NO_PREFIX	-2	/* no prefix was found */
 
-
 void
 usage(char *cp)
 {
@@ -408,7 +417,7 @@
 	(void) textdomain(TEXT_DOMAIN);
 
 	if (argc < 2)
-		usage((char *)NULL);
+		usage(NULL);
 
 	while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) {
 		switch (ch) {
@@ -438,7 +447,7 @@
 			break;
 		case '?':
 		default:
-			usage((char *)NULL);
+			usage(NULL);
 			/* NOTREACHED */
 		}
 	}
@@ -815,7 +824,7 @@
  * Return the name of the host whose address is given.
  */
 char *
-routename(struct sockaddr *sa)
+routename(const struct sockaddr *sa)
 {
 	char *cp;
 	static char line[MAXHOSTNAMELEN + 1];
@@ -1362,6 +1371,31 @@
 			}
 			rcip->ri_flags |= RTF_SETSRC;
 			break;
+		case K_SECATTR:
+			if (!NEXTTOKEN) {
+				syntax_arg_missing(keyword_str);
+				return (B_FALSE);
+			}
+			if ((rcip->ri_cmd == RTM_ADD ||
+			    rcip->ri_cmd == RTM_CHANGE) &&
+			    rcip->ri_rtsa_cnt++ < 1 && is_system_labeled()) {
+				int err;
+
+				if (!rtsa_keyword(tok, &rcip->ri_rtsa, &err,
+				    NULL)) {
+					(void) fprintf(stderr, gettext("route: "
+					    "bad security attribute: %s\n"),
+					    tsol_strerror(err, errno));
+					return (B_FALSE);
+				}
+			}
+			if (rcip->ri_rtsa_cnt > 1) {
+				(void) fprintf(stderr,
+				    gettext("route: can't specify more "
+				    "than one security attribute\n"));
+				return (B_FALSE);
+			}
+			break;
 		default:
 			if (dash_keyword) {
 				syntax_bad_keyword(tok + 1);
@@ -2428,7 +2462,25 @@
 	 */
 	NEXTADDR(RTA_SRC, newrt->ri_src);
 #undef	NEXTADDR
+
+	if (newrt->ri_rtsa_cnt > 0) {
+		/* LINTED: aligned */
+		rtm_ext_t *rtm_ext = (rtm_ext_t *)cp;
+		tsol_rtsecattr_t *rtsecattr;
+
+		rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR;
+		rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(1);
+
+		rtsecattr = (tsol_rtsecattr_t *)(rtm_ext + 1);
+		rtsecattr->rtsa_cnt = 1;
+
+		bcopy(&newrt->ri_rtsa, rtsecattr->rtsa_attr,
+		    sizeof (newrt->ri_rtsa));
+		cp = (char *)(rtsecattr->rtsa_attr + 1);
+	}
+
 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+
 	if (verbose)
 		print_rtmsg(&rtm, l);
 	if (debugonly)
@@ -2522,10 +2574,12 @@
 		    rtm->rtm_version);
 		return;
 	}
-	if (rtm->rtm_msglen > (ushort_t)msglen) {
+	if (rtm->rtm_msglen != msglen) {
 		(void) printf("message length mismatch, in packet %d, "
 		    "returned %d\n",
 		    rtm->rtm_msglen, msglen);
+		if (msglen > rtm->rtm_msglen)
+			msglen = rtm->rtm_msglen;
 	}
 	/*
 	 * Since rtm->rtm_type is unsigned, we'll just check the case of zero
@@ -2536,26 +2590,29 @@
 		    rtm->rtm_type);
 		return;
 	}
-	(void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
+	(void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], msglen);
 	switch (rtm->rtm_type) {
 	case RTM_IFINFO:
 		ifm = (struct if_msghdr *)rtm;
 		(void) printf("if# %d, flags:", ifm->ifm_index);
 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
-		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
+		pmsg_addrs((const char *)(ifm + 1), msglen - sizeof (*ifm),
+		    ifm->ifm_addrs);
 		break;
 	case RTM_NEWADDR:
 	case RTM_DELADDR:
 		ifam = (struct ifa_msghdr *)rtm;
 		(void) printf("metric %d, flags:", ifam->ifam_metric);
 		bprintf(stdout, ifam->ifam_flags, routeflags);
-		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
+		pmsg_addrs((const char *)(ifam + 1), msglen - sizeof (*ifam),
+		    ifam->ifam_addrs);
 		break;
 	default:
 		(void) printf("pid: %ld, seq %d, errno %d, flags:",
 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
 		bprintf(stdout, rtm->rtm_flags, routeflags);
-		pmsg_common(rtm);
+		pmsg_common(rtm, msglen);
+		break;
 	}
 }
 
@@ -2665,50 +2722,76 @@
 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
 	if (rtm->rtm_rmx.rmx_expire)
 		rtm->rtm_rmx.rmx_expire -= time(0);
-	(void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+	(void) printf("%8d%c", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
 #undef lock
 #undef msec
 #define	RTA_IGN	\
 	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC)
 	if (verbose) {
-		pmsg_common(rtm);
-	} else if (rtm->rtm_addrs &~ RTA_IGN) {
-		(void) printf("sockaddrs: ");
-		bprintf(stdout, rtm->rtm_addrs, addrnames);
+		pmsg_common(rtm, msglen);
+	} else {
+		const char *sptr, *endptr;
+		const struct sockaddr *sa;
+		uint_t addrs;
+
+		/* Not verbose; just print out the exceptional cases */
+		if (rtm->rtm_addrs &~ RTA_IGN) {
+			(void) printf("\nsockaddrs: ");
+			bprintf(stdout, rtm->rtm_addrs, addrnames);
+		}
+		sptr = (const char *)(rtm + 1);
+		endptr = (const char *)rtm + msglen;
+		addrs = rtm->rtm_addrs;
+		while (addrs != 0 && sptr + sizeof (*sa) <= endptr) {
+			addrs &= addrs - 1;
+			/* LINTED */
+			sa = (const struct sockaddr *)sptr;
+			ADVANCE(sptr, sa);
+		}
+		if (addrs == 0)
+			pmsg_secattr(sptr, endptr - sptr, "    secattr: ");
 		(void) putchar('\n');
 	}
 #undef	RTA_IGN
 }
 
-void
-pmsg_common(struct rt_msghdr *rtm)
+static void
+pmsg_common(const struct rt_msghdr *rtm, size_t msglen)
 {
 	(void) printf("\nlocks: ");
 	bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames);
 	(void) printf(" inits: ");
 	bprintf(stdout, (int)rtm->rtm_inits, metricnames);
-	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
+	pmsg_addrs((const char *)(rtm + 1), msglen - sizeof (*rtm),
+	    rtm->rtm_addrs);
 }
 
-void
-pmsg_addrs(char *cp, int addrs)
+static void
+pmsg_addrs(const char *cp, size_t msglen, uint_t addrs)
 {
-	struct sockaddr *sa;
+	const struct sockaddr *sa;
+	const char *maxptr;
 	int i;
 
-	if (addrs == 0)
-		return;
-	(void) printf("\nsockaddrs: ");
-	bprintf(stdout, addrs, addrnames);
-	(void) putchar('\n');
-	for (i = 1; i != 0; i <<= 1) {
-		if (i & addrs) {
-			/* LINTED */
-			sa = (struct sockaddr *)cp;
-			(void) printf(" %s", routename(sa));
-			ADVANCE(cp, sa);
+	if (addrs != 0) {
+		(void) printf("\nsockaddrs: ");
+		bprintf(stdout, addrs, addrnames);
+		(void) putchar('\n');
+		maxptr = cp + msglen;
+		for (i = 1; i != 0 && cp + sizeof (*sa) <= maxptr; i <<= 1) {
+			if (i & addrs) {
+				/* LINTED */
+				sa = (const struct sockaddr *)cp;
+				(void) printf(" %s", routename(sa));
+				ADVANCE(cp, sa);
+			}
 		}
+		if (i != 0)
+			msglen = 0;
+		else
+			msglen = maxptr - cp;
 	}
+	pmsg_secattr(cp, msglen, "secattr: ");
 	(void) putchar('\n');
 	(void) fflush(stdout);
 }
@@ -2834,7 +2917,7 @@
 }
 
 int
-salen(struct sockaddr *sa)
+salen(const struct sockaddr *sa)
 {
 	switch (sa->sa_family) {
 	case AF_INET:
@@ -3094,3 +3177,57 @@
 	}
 	return (NULL);
 }
+
+/*
+ * print label security attributes for gateways.
+ */
+static void
+pmsg_secattr(const char *sptr, size_t msglen, const char *labelstr)
+{
+	rtm_ext_t rtm_ext;
+	tsol_rtsecattr_t sp;
+	struct rtsa_s *rtsa = &sp.rtsa_attr[0];
+	const char *endptr;
+	char buf[256];
+	int i;
+
+	if (!is_system_labeled())
+		return;
+
+	endptr = sptr + msglen;
+
+	for (;;) {
+		if (sptr + sizeof (rtm_ext_t) + sizeof (sp) > endptr)
+			return;
+
+		bcopy(sptr, &rtm_ext, sizeof (rtm_ext));
+		sptr += sizeof (rtm_ext);
+		if (rtm_ext.rtmex_type == RTMEX_GATEWAY_SECATTR)
+			break;
+		sptr += rtm_ext.rtmex_len;
+	}
+
+	/* bail if this entry is corrupt or overruns buffer length */
+	if (rtm_ext.rtmex_len < sizeof (sp) ||
+	    sptr + rtm_ext.rtmex_len > endptr)
+		return;
+
+	/* run up just to the end of this extension */
+	endptr = sptr + rtm_ext.rtmex_len;
+
+	bcopy(sptr, &sp, sizeof (sp));
+	sptr += sizeof (sp);
+
+	if (sptr + (sp.rtsa_cnt - 1) * sizeof (*rtsa) != endptr)
+		return;
+
+	for (i = 0; i < sp.rtsa_cnt; i++) {
+		if (i > 0) {
+			/* first element is part of sp initalized above */
+			bcopy(sptr, rtsa, sizeof (*rtsa));
+			sptr += sizeof (*rtsa);
+		}
+		(void) printf("\n%s%s", labelstr, rtsa_to_str(rtsa, buf,
+		    sizeof (buf)));
+	}
+}
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -46,7 +47,8 @@
 include	../../../Makefile.cmd
 
 CPPFLAGS += -I. -I$(SRC)/common/net/dhcp
-LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl
+LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl \
+	-z lazyload -ltsol -z nolazyload
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c	Fri Mar 24 12:29:20 2006 -0800
@@ -53,7 +53,7 @@
 
 #include "snoop.h"
 
-int snaplen;
+static int snaplen;
 char *device = NULL;
 
 /* Global error recovery variables */
@@ -61,12 +61,9 @@
 int snoop_nrecover;			/* number of recoveries on curr pkt */
 int quitting;				/* user termination flag */
 
-extern int encap_levels;		/* variables needing reset on error */
-extern unsigned int total_encap_levels;
-
-struct snoop_handler *snoop_hp;		/* global alarm handler head */
-struct snoop_handler *snoop_tp;		/* global alarm handler tail */
-time_t snoop_nalarm;			/* time of next alarm */
+static struct snoop_handler *snoop_hp;		/* global alarm handler head */
+static struct snoop_handler *snoop_tp;		/* global alarm handler tail */
+static time_t snoop_nalarm;			/* time of next alarm */
 
 /* protected interpreter output areas */
 #define	MAXSUM		8
@@ -76,10 +73,10 @@
 static char *line;
 static char *encap;
 
-int audio;
+static int audio;
 int maxcount;	/* maximum no of packets to capture */
 int count;	/* count of packets captured */
-int sumcount;
+static int sumcount;
 int x_offset = -1;
 int x_length = 0x7fffffff;
 FILE *namefile;
@@ -91,17 +88,15 @@
 #endif
 struct Pf_ext_packetfilt pf;
 
-void usage();
+static void usage(void);
 void show_count();
-void snoop_sigrecover(int sig, siginfo_t *info, void *p);
+static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
 static char *protmalloc(size_t);
 static void resetperm(void);
 
 int
 main(int argc, char **argv)
 {
-	extern char *optarg;
-	extern int optind;
 	int c;
 	int filter = 0;
 	int flags = F_SUM;
@@ -120,8 +115,6 @@
 	char self[MAXHOSTNAMELEN + 1];
 	char *argstr = NULL;
 	void (*proc)();
-	extern void cap_write();
-	extern void process_pkt();
 	char *audiodev;
 	int ret;
 	struct sigaction sigact;
@@ -170,7 +163,7 @@
 	/* Initialize a master signal handler */
 	sigact.sa_handler = NULL;
 	sigact.sa_sigaction = snoop_sigrecover;
-	sigemptyset(&sigact.sa_mask);
+	(void) sigemptyset(&sigact.sa_mask);
 	sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
 
 	/* Register master signal handler */
@@ -231,7 +224,7 @@
 	if (sigsetjmp(jmp_env, 1)) {
 		exit(1);
 	}
-	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+	(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
 
 	while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:vVp:f:c:x:?rqz"))
 				!= EOF) {
@@ -491,7 +484,7 @@
 		net_read(chunksize, filter, proc, flags);
 
 		if (!(flags & F_NOW))
-			printf("\n");
+			(void) printf("\n");
 	}
 
 	if (ocapfile)
@@ -500,7 +493,7 @@
 	return (0);
 }
 
-int tone[] = {
+static int tone[] = {
 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
@@ -524,7 +517,7 @@
 	len = len ? len : 4;
 
 	if (audio) {
-		write(audio, tone, len);
+		(void) write(audio, tone, len);
 	}
 }
 
@@ -561,16 +554,16 @@
 	int i, start;
 
 	if (flags & F_NUM) {
-		sprintf(lp, "%3d ", num);
+		(void) sprintf(lp, "%3d ", num);
 		lp += strlen(lp);
 	}
 	tm = localtime(&tvp->tv_sec);
 
 	if (flags & F_TIME) {
 		if (flags & F_ATIME) {
-			sprintf(lp, "%d:%02d:%d.%05d ",
+			(void) sprintf(lp, "%d:%02d:%d.%05d ",
 				tm->tm_hour, tm->tm_min, tm->tm_sec,
-				tvp->tv_usec / 10);
+				(int)tvp->tv_usec / 10);
 			lp += strlen(lp);
 		} else {
 			if (flags & F_RTIME) {
@@ -586,44 +579,44 @@
 				usec += 1000000;
 				sec  -= 1;
 			}
-			sprintf(lp, "%3d.%05d ", sec, usec / 10);
+			(void) sprintf(lp, "%3d.%05d ", sec, usec / 10);
 			lp += strlen(lp);
 		}
 	}
 
 	if (flags & F_WHO) {
-		sprintf(lp, "%12s -> %-12s ", src, dst);
+		(void) sprintf(lp, "%12s -> %-12s ", src, dst);
 		lp += strlen(lp);
 	}
 
 	if (flags & F_DROPS) {
-		sprintf(lp, "drops: %d ", drops);
+		(void) sprintf(lp, "drops: %d ", drops);
 		lp += strlen(lp);
 	}
 
 	if (flags & F_LEN) {
-		sprintf(lp, "length: %4d  ", len);
+		(void) sprintf(lp, "length: %4d  ", len);
 		lp += strlen(lp);
 	}
 
 	if (flags & F_SUM) {
 		if (flags & F_ALLSUM)
-			printf("________________________________\n");
+			(void) printf("________________________________\n");
 
 		start = flags & F_ALLSUM ? 0 : sumcount - 1;
-		sprintf(encap, "  (%d encap)", total_encap_levels - 1);
-		printf("%s%s%s\n", line, sumline[start],
+		(void) sprintf(encap, "  (%d encap)", total_encap_levels - 1);
+		(void) printf("%s%s%s\n", line, sumline[start],
 		    ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" :
 			encap);
 
 		for (i = start + 1; i < sumcount; i++)
-			printf("%s%s\n", line, sumline[i]);
+			(void) printf("%s%s\n", line, sumline[i]);
 
 		sumcount = 0;
 	}
 
 	if (flags & F_DTAIL) {
-		printf("%s\n\n", detail_line);
+		(void) printf("%s\n\n", detail_line);
 		detail_line[0] = '\0';
 	}
 }
@@ -658,7 +651,7 @@
 	int off, len;
 {
 	if (detail_line[0]) {
-		printf("%s\n", detail_line);
+		(void) printf("%s\n", detail_line);
 		detail_line[0] = '\0';
 	}
 	return (detail_line);
@@ -667,27 +660,32 @@
 /*
  * Print an error.
  * Works like printf (fmt string and variable args)
- * except that it will subsititute an error message
+ * except that it will substitute an error message
  * for a "%m" string (like syslog) and it calls
  * long_jump - it doesn't return to where it was
  * called from - it goes to the last setjmp().
  */
+/* VARARGS1 */
 void
-pr_err(char *fmt, ...)
+pr_err(const char *fmt, ...)
 {
 	va_list ap;
-	char buf[BUFSIZ], *p2;
-	char *p1;
+	char buf[1024], *p2;
+	const char *p1;
 
-	strcpy(buf, "snoop: ");
+	(void) strcpy(buf, "snoop: ");
 	p2 = buf + strlen(buf);
 
-	for (p1 = fmt; *p1; p1++) {
+	/*
+	 * Note that we terminate the buffer with '\n' and '\0'.
+	 */
+	for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) {
 		if (*p1 == '%' && *(p1+1) == 'm') {
-			char *errstr;
+			const char *errstr;
 
-			if ((errstr = strerror(errno)) != (char *)NULL) {
-				(void) strcpy(p2, errstr);
+			if ((errstr = strerror(errno)) != NULL) {
+				*p2 = '\0';
+				(void) strlcat(buf, errstr, sizeof (buf));
 				p2 += strlen(p2);
 			}
 			p1++;
@@ -700,6 +698,7 @@
 	*p2 = '\0';
 
 	va_start(ap, fmt);
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
 	(void) vfprintf(stderr, buf, ap);
 	va_end(ap);
 	snoop_sigrecover(-1, NULL, NULL);	/* global error recovery */
@@ -710,8 +709,8 @@
  * PLEASE keep this up to date!
  * Naive users *love* this stuff.
  */
-void
-usage()
+static void
+usage(void)
 {
 	(void) fprintf(stderr, "\nUsage:  snoop\n");
 	(void) fprintf(stderr,
@@ -793,8 +792,8 @@
 	volatile sigset_t s_mask;
 	volatile int ret = -1;
 
-	sigemptyset((sigset_t *)&s_mask);
-	sigaddset((sigset_t *)&s_mask, SIGALRM);
+	(void) sigemptyset((sigset_t *)&s_mask);
+	(void) sigaddset((sigset_t *)&s_mask, SIGALRM);
 	if (s_sec < 0)
 		return (-1);
 
@@ -812,7 +811,7 @@
 			snoop_hp = snoop_tp = (struct snoop_handler *)sh;
 
 			snoop_nalarm = sh->s_time;
-			alarm(sh->s_time - now);
+			(void) alarm(sh->s_time - now);
 		} else {
 			snoop_tp->s_next = (struct snoop_handler *)sh;
 			snoop_tp = (struct snoop_handler *)sh;
@@ -905,7 +904,7 @@
  * out the signal blocking.
  */
 /*ARGSUSED*/
-void
+static void
 snoop_sigrecover(int sig, siginfo_t *info, void *p)
 {
 	volatile time_t now;
@@ -934,7 +933,7 @@
 		/* Setup next alarm */
 		if (nalarm) {
 			snoop_nalarm = nalarm;
-			alarm(nalarm - now);
+			(void) alarm(nalarm - now);
 		} else {
 			snoop_nalarm = 0;
 		}
@@ -979,7 +978,7 @@
 			return;
 		}
 		if (snoop_nrecover >= SNOOP_MAXRECOVER) {
-			fprintf(stderr,
+			(void) fprintf(stderr,
 				"snoop: WARNING: skipping from packet %d\n",
 				count);
 			snoop_nrecover = 0;
@@ -988,13 +987,13 @@
 			return;
 		}
 	} else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
-		fprintf(stderr,
+		(void) fprintf(stderr,
 			"snoop: ERROR: cannot recover from packet %d\n", count);
 		exit(1);
 	}
 
 #ifdef DEBUG
-	fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
+	(void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
 #endif /* DEBUG */
 
 	/*
@@ -1006,7 +1005,8 @@
 		return;
 	} else if (sig != -1 && sig != SIGALRM) {
 		/* Inform user that snoop has taken a fault */
-		fprintf(stderr, "WARNING: received signal %d from packet %d\n",
+		(void) fprintf(stderr,
+		    "WARNING: received signal %d from packet %d\n",
 				sig, count);
 	}
 
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,6 +34,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/bufmod.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
@@ -127,6 +127,7 @@
 extern char *get_sum_line(void);
 extern char *get_detail_line(int, int);
 extern struct timeval prev_time;
+extern void process_pkt(struct sb_hdr *, char *, int, int);
 extern char *getflag(int, int, char *, char *);
 extern void show_header(char *, char *, int);
 extern void xdr_init(char *, int);
@@ -173,6 +174,7 @@
 extern int pf_compile(char *, int);
 extern void compile(char *, int);
 extern void load_names(char *);
+extern void cap_write(struct sb_hdr *, char *, int, int);
 extern void cap_open_read(char *);
 extern void cap_open_write(char *);
 extern void cap_read(int, int, int, void (*)(), int);
@@ -187,9 +189,9 @@
 extern void show_line(char *);
 extern char *getxdr_time(void);
 extern char *showxdr_time(char *);
-extern char *addrtoname(int, void *);
+extern char *addrtoname(int, const void *);
 extern char *show_string(const char *, int, int);
-extern void pr_err(char *, ...);
+extern void pr_err(const char *, ...);
 extern void check_retransmit(char *, ulong_t);
 extern char *nameof_prog(int);
 extern char *getproto(int);
@@ -219,14 +221,40 @@
 extern void interpret_ldap(int, char *, int, int, int);
 extern void interpret_icmp(int, struct icmp *, int, int);
 extern void interpret_icmpv6(int, icmp6_t *, int, int);
-extern int interpret_ip(int, struct ip *, int);
-extern int interpret_ipv6(int, ip6_t *, int);
+extern int interpret_ip(int, const struct ip *, int);
+extern int interpret_ipv6(int, const ip6_t *, int);
 extern int interpret_ppp(int, uchar_t *, int);
 extern int interpret_pppoe(int, poep_t *, int);
+struct tcphdr;
+extern int interpret_tcp(int, struct tcphdr *, int, int);
+struct udphdr;
+extern int interpret_udp(int, struct udphdr *, int, int);
+extern int interpret_esp(int, uint8_t *, int, int);
+extern int interpret_ah(int, uint8_t *, int, int);
+struct sctp_hdr;
+extern void interpret_sctp(int, struct sctp_hdr *, int, int);
+extern void interpret_mip_cntrlmsg(int, uchar_t *, int);
+struct dhcp;
+extern int interpret_dhcp(int, struct dhcp *, int);
+struct tftphdr;
+extern int interpret_tftp(int, struct tftphdr *, int);
+extern int interpret_http(int, char *, int);
+struct ntpdata;
+extern int interpret_ntp(int, struct ntpdata *, int);
+extern void interpret_netbios_ns(int, uchar_t *, int);
+extern void interpret_netbios_datagram(int, uchar_t *, int);
+extern void interpret_netbios_ses(int, uchar_t *, int);
+extern void interpret_slp(int, char *, int);
+struct rip;
+extern int interpret_rip(int, struct rip *, int);
+struct rip6;
+extern int interpret_rip6(int, struct rip6 *, int);
+extern int interpret_socks_call(int, char *, int);
+extern int interpret_socks_reply(int, char *, int);
 extern void init_ldap(void);
 extern boolean_t arp_for_ether(char *, struct ether_addr *);
 extern char *ether_ouiname(uint32_t);
-char *tohex(char *p, int len);
+extern char *tohex(char *p, int len);
 extern char *printether(struct ether_addr *);
 extern char *print_ethertype(int);
 
@@ -257,6 +285,17 @@
 
 extern char *dlc_header;
 
+extern char *src_name, *dst_name;
+
+extern char *prot_prefix;
+extern char *prot_nest_prefix;
+extern char *prot_title;
+
+/* Keep track of how many nested IP headers we have. */
+extern unsigned int encap_levels, total_encap_levels;
+
+extern int quitting;
+
 /*
  * Global error recovery routine: used to reset snoop variables after
  * catastrophic failure.
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -57,27 +56,37 @@
 
 #include "snoop.h"
 
-void scan();
+/*
+ * Old header format.
+ * Actually two concatenated structs:  nit_bufhdr + nit_head
+ */
+struct ohdr {
+	/* nit_bufhdr */
+	int	o_msglen;
+	int	o_totlen;
+	/* nit_head */
+	struct timeval o_time;
+	int	o_drops;
+	int	o_len;
+};
+
+static void scan(char *, int, int, int, int, void (*)(), int, int, int);
 void convert_to_network();
 void convert_from_network();
-void convert_old();
-extern int quitting;
+static void convert_old(struct ohdr *);
 extern sigjmp_buf jmp_env, ojmp_env;
-int netfd;
-union DL_primitives netdl;			/* info_ack for interface */
-char *bufp;	/* pointer to read buffer */
+static int netfd;
+static union DL_primitives netdl;		/* info_ack for interface */
+static char *bufp;	/* pointer to read buffer */
 
-extern unsigned int encap_levels;
-
-static int strioctl(int, int, int, int, char *);
+static int strioctl(int, int, int, int, void *);
 
 /*
  * Convert a device id to a ppa value
  * e.g. "le0" -> 0
  */
-int
-device_ppa(device)
-	char *device;
+static int
+device_ppa(char *device)
 {
 	char *p;
 	char *tp;
@@ -97,9 +106,8 @@
  * Level 1 devices: "le0" -> "/dev/le0".
  * Level 2 devices: "le0" -> "/dev/le".
  */
-char *
-device_path(device)
-	char *device;
+static char *
+device_path(char *device)
 {
 	static char buff[IF_NAMESIZE + 1];
 	struct stat st;
@@ -223,8 +231,9 @@
 
 	/* allow limited functionality even is interface isn't known */
 	if (interface->mac_type == -1) {
-		fprintf(stderr, "snoop: WARNING: Mac Type = %x not supported\n",
-			netdl.info_ack.dl_mac_type);
+		fprintf(stderr,
+		    "snoop: WARNING: Mac Type = %lx not supported\n",
+		    netdl.info_ack.dl_mac_type);
 	}
 
 	/* for backward compatibility, allow known interface mtu_sizes */
@@ -244,6 +253,7 @@
  * push the streams buffer module and packet filter module, set various buffer
  * parameters.
  */
+/* ARGSUSED */
 void
 initdevice(device, snaplen, chunksize, timeout, fp, ppa)
 	char *device;
@@ -252,7 +262,6 @@
 	struct Pf_ext_packetfilt *fp;
 	int ppa;
 {
-	union DL_primitives dl;
 	extern int Pflg;
 
 	/*
@@ -281,7 +290,7 @@
 	dlpromiscon(netfd, DL_PROMISC_SAP);
 
 	if (ioctl(netfd, DLIOCRAW, 0) < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("ioctl: DLIOCRAW: %s: %m", device_path(device));
 	}
 
@@ -290,38 +299,38 @@
 		 * push and configure the packet filtering module
 		 */
 		if (ioctl(netfd, I_PUSH, "pfmod") < 0) {
-			close(netfd);
+			(void) close(netfd);
 			pr_err("ioctl: I_PUSH pfmod: %s: %m",
 			    device_path(device));
 		}
 
 		if (strioctl(netfd, PFIOCSETF, -1, sizeof (*fp),
 		    (char *)fp) < 0) {
-			close(netfd);
+			(void) close(netfd);
 			pr_err("PFIOCSETF: %s: %m", device_path(device));
 		}
 	}
 
 	if (ioctl(netfd, I_PUSH, "bufmod") < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("push bufmod: %s: %m", device_path(device));
 	}
 
 	if (strioctl(netfd, SBIOCSTIME, -1, sizeof (struct timeval),
 	    (char *)timeout) < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("SBIOCSTIME: %s: %m", device_path(device));
 	}
 
 	if (strioctl(netfd, SBIOCSCHUNK, -1, sizeof (uint_t),
 	    (char *)&chunksize) < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("SBIOCGCHUNK: %s: %m", device_path(device));
 	}
 
 	if (strioctl(netfd, SBIOCSSNAP, -1, sizeof (uint_t),
 	    (char *)&snaplen) < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("SBIOCSSNAP: %s: %m", device_path(device));
 	}
 
@@ -330,7 +339,7 @@
 	 * accumulated before the device reached its final configuration.
 	 */
 	if (ioctl(netfd, I_FLUSH, FLUSHR) < 0) {
-		close(netfd);
+		(void) close(netfd);
 		pr_err("I_FLUSH: %s: %m", device_path(device));
 	}
 }
@@ -383,7 +392,7 @@
 	}
 
 	free(bufp);
-	close(netfd);
+	(void) close(netfd);
 
 	if (!quitting) {
 		if (r < 0)
@@ -422,13 +431,9 @@
 }
 #endif /* DEBUG */
 
-void
-scan(buf, len, filter, cap, old, proc, first, last, flags)
-	char *buf;
-	int len, filter, cap, old;
-	void (*proc)();
-	int first, last;
-	int flags;
+static void
+scan(char *buf, int len, int filter, int cap, int old, void (*proc)(),
+    int first, int last, int flags)
 {
 	volatile char *bp, *bufstop;
 	volatile struct sb_hdr *hdrp;
@@ -481,7 +486,7 @@
 			 * capture file, convert the header.
 			 */
 			if (old) {
-				convert_old(hdrp);
+				convert_old((struct ohdr *)hdrp);
 			}
 
 			nhdrp = &nhdr;
@@ -685,34 +690,33 @@
  * |	 word 0	   |	 word 1	   |	 word 2	   |	 word 3
  *
  */
-const char *snoop_id = "snoop\0\0\0";
-const int snoop_idlen = 8;
-const int snoop_version = 2;
+static const char *snoop_id = "snoop\0\0\0";
+static const int snoop_idlen = 8;
+static const int snoop_version = 2;
 
 void
 cap_open_write(name)
 	char *name;
 {
 	int vers;
-	int rc;
 
 	capfile_out = open(name, O_CREAT | O_TRUNC | O_RDWR, 0666);
 	if (capfile_out < 0)
 		pr_err("%s: %m", name);
 
 	vers = htonl(snoop_version);
-	if ((rc = nwrite(capfile_out, snoop_id, snoop_idlen)) == -1)
+	if (nwrite(capfile_out, snoop_id, snoop_idlen) == -1)
 		cap_write_error("snoop_id");
 
-	if ((rc = nwrite(capfile_out, &vers, sizeof (int))) == -1)
+	if (nwrite(capfile_out, &vers, sizeof (int)) == -1)
 		cap_write_error("version");
 }
 
 
 void
-cap_close()
+cap_close(void)
 {
-	close(capfile_out);
+	(void) close(capfile_out);
 }
 
 static char *cap_buffp = NULL;
@@ -737,7 +741,7 @@
 	cap_len = st.st_size;
 
 	cap_buffp = mmap(0, cap_len, PROT_READ, MAP_PRIVATE, capfile_in, 0);
-	close(capfile_in);
+	(void) close(capfile_in);
 	if ((int)cap_buffp == -1)
 		pr_err("couldn't mmap %s: %m", name);
 
@@ -810,9 +814,10 @@
 
 	scan(cap_buffp, cap_len, filter, 1, !cap_new, proc, first, last, flags);
 
-	munmap(cap_buffp, cap_len);
+	(void) munmap(cap_buffp, cap_len);
 }
 
+/* ARGSUSED */
 void
 cap_write(hdrp, pktp, num, flags)
 	struct sb_hdr *hdrp;
@@ -823,7 +828,6 @@
 	static int first = 1;
 	struct sb_hdr nhdr;
 	extern boolean_t qflg;
-	int rc;
 
 	if (hdrp == NULL)
 		return;
@@ -831,7 +835,7 @@
 	if (first) {
 		first = 0;
 		mac = htonl(interface->mac_type);
-		if ((rc = nwrite(capfile_out, &mac, sizeof (int))) == -1)
+		if (nwrite(capfile_out, &mac, sizeof (int)) == -1)
 			cap_write_error("mac_type");
 	}
 
@@ -847,10 +851,10 @@
 	nhdr.sbh_timestamp.tv_sec = htonl(hdrp->sbh_timestamp.tv_sec);
 	nhdr.sbh_timestamp.tv_usec = htonl(hdrp->sbh_timestamp.tv_usec);
 
-	if ((rc = nwrite(capfile_out, &nhdr, sizeof (nhdr))) == -1)
+	if (nwrite(capfile_out, &nhdr, sizeof (nhdr)) == -1)
 		cap_write_error("packet header");
 
-	if ((rc = nwrite(capfile_out, pktp, pktlen)) == -1)
+	if (nwrite(capfile_out, pktp, pktlen) == -1)
 		cap_write_error("packet");
 
 	if (! qflg)
@@ -858,26 +862,11 @@
 }
 
 /*
- * Old header format.
- * Actually two concatenated structs:  nit_bufhdr + nit_head
- */
-struct ohdr {
-	/* nit_bufhdr */
-	int	o_msglen;
-	int	o_totlen;
-	/* nit_head */
-	struct timeval o_time;
-	int	o_drops;
-	int	o_len;
-};
-
-/*
  * Convert a packet header from
  * old to new format.
  */
-void
-convert_old(ohdrp)
-	struct ohdr *ohdrp;
+static void
+convert_old(struct ohdr *ohdrp)
 {
 	struct sb_hdr nhdr;
 
@@ -891,7 +880,7 @@
 }
 
 static int
-strioctl(int fd, int cmd, int timout, int len, char *dp)
+strioctl(int fd, int cmd, int timout, int len, void *dp)
 {
 	struct	strioctl	sioc;
 	int	rc;
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -135,7 +135,7 @@
 #define	OPTIONS_ARRAY_SIZE	78
 
 int
-interpret_dhcp(int flags, PKT *dp, int len)
+interpret_dhcp(int flags, struct dhcp *dp, int len)
 {
 	if (flags & F_SUM) {
 		if ((memcmp(dp->cookie, bootmagic, sizeof (bootmagic)) == 0) &&
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,7 +27,6 @@
 
 
 #include <stdio.h>
-#include <ctype.h>
 #include <string.h>
 #include <fcntl.h>
 #include <string.h>
@@ -37,7 +35,6 @@
 
 #include <sys/stropts.h>
 #include <sys/socket.h>
-#include <sys/sockio.h>
 #include <net/if.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
@@ -46,10 +43,14 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <netinet/if_ether.h>
+#include <inet/ip.h>
 #include <inet/ip6.h>
-#include <inet/ipsecah.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <tsol/label.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/label_macro.h>
+
 #include "snoop.h"
 
 
@@ -67,34 +68,29 @@
 #define	SNOOP_ESP	0x20U
 #define	SNOOP_IPV6	0x40U
 
-extern char *dlc_header;
-
-static void prt_routing_hdr();
-static void prt_fragment_hdr();
-static void prt_hbh_options();
-static void prt_dest_options();
-static void print_route();
-static void print_ipoptions();
-char *getproto();
+static void prt_routing_hdr(int, const struct ip6_rthdr *);
+static void prt_fragment_hdr(int, const struct ip6_frag *);
+static void prt_hbh_options(int, const struct ip6_hbh *);
+static void prt_dest_options(int, const struct ip6_dest *);
+static void print_route(const uchar_t *);
+static void print_ipoptions(const uchar_t *, int);
+static void print_ripso(const uchar_t *);
+static void print_cipso(const uchar_t *);
 
 /* Keep track of how many nested IP headers we have. */
 unsigned int encap_levels;
 unsigned int total_encap_levels = 1;
 
 int
-interpret_ip(flags, ip, fraglen)
-	int flags;
-	struct ip *ip;
-	int fraglen;
+interpret_ip(int flags, const struct ip *ip, int fraglen)
 {
-	char *data;
+	uchar_t *data;
 	char buff[24];
 	boolean_t isfrag = B_FALSE;
 	boolean_t morefrag;
 	uint16_t fragoffset;
 	int hdrlen;
 	uint16_t iplen, uitmp;
-	extern char *src_name, *dst_name;
 
 	if (ip->ip_v == IPV6_VERSION) {
 		iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen);
@@ -108,7 +104,7 @@
 	total_encap_levels++;
 
 	hdrlen = ip->ip_hl * 4;
-	data = ((char *)ip) + hdrlen;
+	data = ((uchar_t *)ip) + hdrlen;
 	iplen = ntohs(ip->ip_len) - hdrlen;
 	fraglen -= hdrlen;
 	if (fraglen > iplen)
@@ -163,80 +159,74 @@
 	if (flags & F_DTAIL) {
 		show_header("IP:   ", "IP Header", iplen);
 		show_space();
-		(void) snprintf(get_line((char *)ip - dlc_header, 1),
-		    get_line_remain(), "Version = %d", ip->ip_v);
-		(void) snprintf(get_line((char *)ip - dlc_header, 1),
-		    get_line_remain(), "Header length = %d bytes", hdrlen);
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "Type of service = 0x%02x", ip->ip_tos);
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      xxx. .... = %d (precedence)",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Version = %d", ip->ip_v);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Header length = %d bytes", hdrlen);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Type of service = 0x%02x", ip->ip_tos);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "      xxx. .... = %d (precedence)",
 		    ip->ip_tos >> 5);
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      %s",
-		    getflag(ip->ip_tos, IPTOS_LOWDELAY,
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "      %s", getflag(ip->ip_tos, IPTOS_LOWDELAY,
 		    "low delay", "normal delay"));
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(ip->ip_tos, IPTOS_THROUGHPUT,
 		    "high throughput", "normal throughput"));
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(ip->ip_tos, IPTOS_RELIABILITY,
 		    "high reliability", "normal reliability"));
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(ip->ip_tos, IPTOS_ECT,
 		    "ECN capable transport", "not ECN capable transport"));
-		(void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(ip->ip_tos, IPTOS_CE,
 		    "ECN congestion experienced",
 		    "no ECN congestion experienced"));
 		/* warning: ip_len is signed in netinet/ip.h */
 		uitmp = ntohs(ip->ip_len);
-		(void) snprintf(get_line((char *)&ip->ip_len - dlc_header, 2),
-		    get_line_remain(), "Total length = %u bytes%s", uitmp,
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Total length = %u bytes%s", uitmp,
 		    iplen > fraglen ? " -- truncated" : "");
-		(void) snprintf(get_line((char *)&ip->ip_id - dlc_header, 2),
-		    get_line_remain(), "Identification = %d", ntohs(ip->ip_id));
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Identification = %d", ntohs(ip->ip_id));
 		/* warning: ip_off is signed in netinet/ip.h */
 		uitmp = ntohs(ip->ip_off);
-		(void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1),
-		    get_line_remain(), "Flags = 0x%x", uitmp >> 12);
-		(void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Flags = 0x%x", uitmp >> 12);
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(uitmp >> 8, IP_DF >> 8,
 		    "do not fragment", "may fragment"));
-		(void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1),
-		    get_line_remain(), "      %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
 		    getflag(uitmp >> 8, IP_MF >> 8,
 		    "more fragments", "last fragment"));
-		(void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 2),
-		    get_line_remain(), "Fragment offset = %u bytes",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Fragment offset = %u bytes",
 		    fragoffset);
-		(void) snprintf(get_line((char *)&ip->ip_ttl - dlc_header, 1),
-		    get_line_remain(), "Time to live = %d seconds/hops",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Time to live = %d seconds/hops",
 		    ip->ip_ttl);
-		(void) snprintf(get_line((char *)&ip->ip_p - dlc_header, 1),
-		    get_line_remain(), "Protocol = %d (%s)", ip->ip_p,
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Protocol = %d (%s)", ip->ip_p,
 		    getproto(ip->ip_p));
 		/*
 		 * XXX need to compute checksum and print whether it's correct
 		 */
-		(void) snprintf(get_line((char *)&ip->ip_sum - dlc_header, 1),
-		    get_line_remain(), "Header checksum = %04x",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Header checksum = %04x",
 		    ntohs(ip->ip_sum));
-		(void) snprintf(get_line((char *)&ip->ip_src - dlc_header, 1),
-		    get_line_remain(), "Source address = %s, %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Source address = %s, %s",
 		    inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src));
-		(void) snprintf(get_line((char *)&ip->ip_dst - dlc_header, 1),
-		    get_line_remain(), "Destination address = %s, %s",
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Destination address = %s, %s",
 		    inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst));
 
 		/* Print IP options - if any */
 
-		print_ipoptions(ip + 1, hdrlen - sizeof (struct ip));
+		print_ipoptions((const uchar_t *)(ip + 1),
+		    hdrlen - sizeof (struct ip));
 		show_space();
 	}
 
@@ -248,8 +238,7 @@
 	 * of a fragmented packet.
 	 */
 	if (flags & F_DTAIL && fragoffset != 0) {
-		(void) snprintf(get_detail_line(data - dlc_header, iplen),
-		    MAXLINE,
+		(void) snprintf(get_detail_line(0, 0), MAXLINE,
 		    "%s:  [%d byte(s) of data, continuation of IP ident=%d]",
 		    getproto(ip->ip_p),
 		    iplen,
@@ -262,12 +251,14 @@
 			case IPPROTO_IP:
 				break;
 			case IPPROTO_ENCAP:
-				(void) interpret_ip(flags, (struct ip *)data,
-				    fraglen);
+				(void) interpret_ip(flags,
+				    /* LINTED: alignment */
+				    (const struct ip *)data, fraglen);
 				break;
 			case IPPROTO_ICMP:
-				interpret_icmp(flags, (struct icmp *)data,
-				    iplen, fraglen);
+				(void) interpret_icmp(flags,
+				    /* LINTED: alignment */
+				    (struct icmp *)data, iplen, fraglen);
 				break;
 			case IPPROTO_IGMP:
 				interpret_igmp(flags, data, iplen, fraglen);
@@ -275,14 +266,17 @@
 			case IPPROTO_GGP:
 				break;
 			case IPPROTO_TCP:
-				interpret_tcp(flags, data, iplen, fraglen);
+				(void) interpret_tcp(flags,
+				    (struct tcphdr *)data, iplen, fraglen);
 				break;
 
 			case IPPROTO_ESP:
-				interpret_esp(flags, data, iplen, fraglen);
+				(void) interpret_esp(flags, data, iplen,
+				    fraglen);
 				break;
 			case IPPROTO_AH:
-				interpret_ah(flags, data, iplen, fraglen);
+				(void) interpret_ah(flags, data, iplen,
+				    fraglen);
 				break;
 
 			case IPPROTO_OSPF:
@@ -293,7 +287,8 @@
 			case IPPROTO_PUP:
 				break;
 			case IPPROTO_UDP:
-				interpret_udp(flags, data, iplen, fraglen);
+				(void) interpret_udp(flags,
+				    (struct udphdr *)data, iplen, fraglen);
 				break;
 
 			case IPPROTO_IDP:
@@ -302,11 +297,13 @@
 			case IPPROTO_RAW:
 				break;
 			case IPPROTO_IPV6:	/* IPV6 encap */
+				/* LINTED: alignment */
 				(void) interpret_ipv6(flags, (ip6_t *)data,
 				    iplen);
 				break;
 			case IPPROTO_SCTP:
-				interpret_sctp(flags, data, iplen, fraglen);
+				(void) interpret_sctp(flags,
+				    (struct sctp_hdr *)data, iplen, fraglen);
 				break;
 			}
 		}
@@ -317,14 +314,10 @@
 }
 
 int
-interpret_ipv6(flags, ip6h, fraglen)
-	int flags;
-	ip6_t *ip6h;
-	int fraglen;
+interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen)
 {
 	uint8_t *data;
 	int hdrlen, iplen;
-	extern char *src_name, *dst_name;
 	int version, flow, class;
 	uchar_t proto;
 	boolean_t isfrag = B_FALSE;
@@ -365,8 +358,8 @@
 	 * will not affect the detailed printing of the packet.
 	 */
 	if (flags & F_SUM) {
-		(void) sprintf(get_sum_line(), "IPv6  S=%s D=%s LEN=%d "
-		    "HOPS=%d CLASS=0x%x FLOW=0x%x",
+		(void) snprintf(get_sum_line(), MAXLINE,
+		    "IPv6  S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x",
 		    src_name, dst_name, iplen, ip6h->ip6_hops, class, flow);
 	} else if (flags & F_DTAIL) {
 
@@ -392,22 +385,22 @@
 		show_header("IPv6:   ", "IPv6 Header", iplen);
 		show_space();
 
-		(void) sprintf(get_line((char *)ip6h - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Version = %d", version);
-		(void) sprintf(get_line((char *)ip6h - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Traffic Class = %d", class);
-		(void) sprintf(get_line((char *)&ip6h->ip6_vcf - dlc_header, 4),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Flow label = 0x%x", flow);
-		(void) sprintf(get_line((char *)&ip6h->ip6_plen -
-		    dlc_header, 2), "Payload length = %d", iplen);
-		(void) sprintf(get_line((char *)&ip6h->ip6_nxt -
-		    dlc_header, 1), "Next Header = %d (%s)", proto,
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Payload length = %d", iplen);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Next Header = %d (%s)", proto,
 		    getproto(proto));
-		(void) sprintf(get_line((char *)&ip6h->ip6_hops -
-		    dlc_header, 1), "Hop Limit = %d", ip6h->ip6_hops);
-		(void) sprintf(get_line((char *)&ip6h->ip6_src - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Hop Limit = %d", ip6h->ip6_hops);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Source address = %s%s", src_addrstr, print_srcname);
-		(void) sprintf(get_line((char *)&ip6h->ip6_dst - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Destination address = %s%s", dst_addrstr, print_dstname);
 
 		show_space();
@@ -440,10 +433,13 @@
 		case IPPROTO_IP:
 			break;
 		case IPPROTO_ENCAP:
-			(void) interpret_ip(flags, (struct ip *)data, fraglen);
+			/* LINTED: alignment */
+			(void) interpret_ip(flags, (const struct ip *)data,
+			    fraglen);
 			break;
 		case IPPROTO_ICMPV6:
-			interpret_icmpv6(flags, (icmp6_t *)data, iplen,
+			/* LINTED: alignment */
+			(void) interpret_icmpv6(flags, (icmp6_t *)data, iplen,
 			    fraglen);
 			break;
 		case IPPROTO_IGMP:
@@ -452,19 +448,21 @@
 		case IPPROTO_GGP:
 			break;
 		case IPPROTO_TCP:
-			interpret_tcp(flags, data, iplen, fraglen);
+			(void) interpret_tcp(flags, (struct tcphdr *)data,
+			    iplen, fraglen);
 			break;
 		case IPPROTO_ESP:
-			interpret_esp(flags, data, iplen, fraglen);
+			(void) interpret_esp(flags, data, iplen, fraglen);
 			break;
 		case IPPROTO_AH:
-			interpret_ah(flags, data, iplen, fraglen);
+			(void) interpret_ah(flags, data, iplen, fraglen);
 			break;
 		case IPPROTO_EGP:
 		case IPPROTO_PUP:
 			break;
 		case IPPROTO_UDP:
-			interpret_udp(flags, data, iplen, fraglen);
+			(void) interpret_udp(flags, (struct udphdr *)data,
+			    iplen, fraglen);
 			break;
 		case IPPROTO_IDP:
 		case IPPROTO_HELLO:
@@ -472,10 +470,13 @@
 		case IPPROTO_RAW:
 			break;
 		case IPPROTO_IPV6:
-			(void) interpret_ipv6(flags, (ip6_t *)data, iplen);
+			/* LINTED: alignment */
+			(void) interpret_ipv6(flags, (const ip6_t *)data,
+			    iplen);
 			break;
 		case IPPROTO_SCTP:
-			interpret_sctp(flags, data, iplen, fraglen);
+			(void) interpret_sctp(flags, (struct sctp_hdr *)data,
+			    iplen, fraglen);
 			break;
 		case IPPROTO_OSPF:
 			interpret_ospf6(flags, data, iplen, fraglen);
@@ -518,7 +519,6 @@
 		 * header.
 		 */
 		if (*fraglen < 2) {
-			proto = IPPROTO_NONE;
 			return (extmask);
 		}
 
@@ -527,7 +527,6 @@
 			ipv6ext_hbh = (struct ip6_hbh *)data_ptr;
 			exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8;
 			if (*fraglen <= exthdrlen) {
-				proto = IPPROTO_NONE;
 				return (extmask);
 			}
 			prt_hbh_options(flags, ipv6ext_hbh);
@@ -538,7 +537,6 @@
 			ipv6ext_dest = (struct ip6_dest *)data_ptr;
 			exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8;
 			if (*fraglen <= exthdrlen) {
-				proto = IPPROTO_NONE;
 				return (extmask);
 			}
 			prt_dest_options(flags, ipv6ext_dest);
@@ -549,7 +547,6 @@
 			ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr;
 			exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8;
 			if (*fraglen <= exthdrlen) {
-				proto = IPPROTO_NONE;
 				return (extmask);
 			}
 			prt_routing_hdr(flags, ipv6ext_rthdr);
@@ -557,10 +554,10 @@
 			proto = ipv6ext_rthdr->ip6r_nxt;
 			break;
 		case IPPROTO_FRAGMENT:
+			/* LINTED: alignment */
 			ipv6ext_frag = (struct ip6_frag *)data_ptr;
 			exthdrlen = sizeof (struct ip6_frag);
 			if (*fraglen <= exthdrlen) {
-				proto = IPPROTO_NONE;
 				return (extmask);
 			}
 			prt_fragment_hdr(flags, ipv6ext_frag);
@@ -593,66 +590,81 @@
 }
 
 static void
-print_ipoptions(opt, optlen)
-	uchar_t *opt;
-	int optlen;
+print_ipoptions(const uchar_t *opt, int optlen)
 {
 	int len;
+	int remain;
 	char *line;
+	const char *truncstr;
 
 	if (optlen <= 0) {
-		(void) sprintf(get_line((char *)&opt - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "No options");
 		return;
 	}
 
-	(void) sprintf(get_line((char *)&opt - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Options: (%d bytes)", optlen);
 
 	while (optlen > 0) {
-		line = get_line((char *)&opt - dlc_header, 1);
+		line = get_line(0, 0);
+		remain = get_line_remain();
 		len = opt[1];
+		truncstr = len > optlen ? "?" : "";
 		switch (opt[0]) {
 		case IPOPT_EOL:
-			(void) strcpy(line, "  - End of option list");
+			(void) strlcpy(line, "  - End of option list", remain);
 			return;
 		case IPOPT_NOP:
-			(void) strcpy(line, "  - No op");
+			(void) strlcpy(line, "  - No op", remain);
 			len = 1;
 			break;
 		case IPOPT_RR:
-			(void) sprintf(line, "  - Record route (%d bytes)",
-			    len);
+			(void) snprintf(line, remain,
+			    "  - Record route (%d bytes%s)", len, truncstr);
 			print_route(opt);
 			break;
 		case IPOPT_TS:
-			(void) sprintf(line, "  - Time stamp (%d bytes)", len);
+			(void) snprintf(line, remain,
+			    "  - Time stamp (%d bytes%s)", len, truncstr);
 			break;
 		case IPOPT_SECURITY:
-			(void) sprintf(line, "  - Security (%d bytes)", len);
+			(void) snprintf(line, remain, "  - RIPSO (%d bytes%s)",
+			    len, truncstr);
+			print_ripso(opt);
+			break;
+		case IPOPT_COMSEC:
+			(void) snprintf(line, remain, "  - CIPSO (%d bytes%s)",
+			    len, truncstr);
+			print_cipso(opt);
 			break;
 		case IPOPT_LSRR:
-			(void) sprintf(line,
-			    "  - Loose source route (%d bytes)", len);
+			(void) snprintf(line, remain,
+			    "  - Loose source route (%d bytes%s)", len,
+			    truncstr);
 			print_route(opt);
 			break;
 		case IPOPT_SATID:
-			(void) sprintf(line, "  - SATNET Stream id (%d bytes)",
-			    len);
+			(void) snprintf(line, remain,
+			    "  - SATNET Stream id (%d bytes%s)",
+			    len, truncstr);
 			break;
 		case IPOPT_SSRR:
-			(void) sprintf(line,
-			    "  - Strict source route, (%d bytes)", len);
+			(void) snprintf(line, remain,
+			    "  - Strict source route, (%d bytes%s)", len,
+			    truncstr);
 			print_route(opt);
 			break;
 		default:
-			sprintf(line, "  - Option %d (unknown - %d bytes) %s",
-			    opt[0], len, tohex((char *)&opt[2], len - 2));
+			(void) snprintf(line, remain,
+			    "  - Option %d (unknown - %d bytes%s) %s",
+			    opt[0], len, truncstr,
+			    tohex((char *)&opt[2], len - 2));
 			break;
 		}
 		if (len <= 0) {
-			(void) sprintf(line, "  - Incomplete option len %d",
-				len);
+			(void) snprintf(line, remain,
+			    "  - Incomplete option len %d", len);
 			break;
 		}
 		opt += len;
@@ -661,17 +673,16 @@
 }
 
 static void
-print_route(opt)
-	uchar_t *opt;
+print_route(const uchar_t *opt)
 {
-	int len, pointer;
+	int len, pointer, remain;
 	struct in_addr addr;
 	char *line;
 
 	len = opt[1];
 	pointer = opt[2];
 
-	(void) sprintf(get_line((char *)(&opt + 2) - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "    Pointer = %d", pointer);
 
 	pointer -= IPOPT_MINOFF;
@@ -679,15 +690,16 @@
 	len -= (IPOPT_OFFSET + 1);
 
 	while (len > 0) {
-		line = get_line((char *)&(opt) - dlc_header, 4);
+		line = get_line(0, 0);
+		remain = get_line_remain();
 		memcpy((char *)&addr, opt, sizeof (addr));
 		if (addr.s_addr == INADDR_ANY)
-			(void) strcpy(line, "      -");
+			(void) strlcpy(line, "      -", remain);
 		else
-			(void) sprintf(line, "      %s",
+			(void) snprintf(line, remain, "      %s",
 			    addrtoname(AF_INET, &addr));
 		if (pointer == 0)
-			(void) strcat(line, "  <-- (current)");
+			(void) strlcat(line, "  <-- (current)", remain);
 
 		opt += sizeof (addr);
 		len -= sizeof (addr);
@@ -696,8 +708,7 @@
 }
 
 char *
-getproto(p)
-	int p;
+getproto(int p)
 {
 	switch (p) {
 	case IPPROTO_HOPOPTS:	return ("IPv6-HopOpts");
@@ -728,9 +739,7 @@
 }
 
 static void
-prt_routing_hdr(flags, ipv6ext_rthdr)
-	int flags;
-	struct ip6_rthdr *ipv6ext_rthdr;
+prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr)
 {
 	uint8_t nxt_hdr;
 	uint8_t type;
@@ -755,13 +764,13 @@
 	show_header("IPv6-Route:  ", "IPv6 Routing Header", 0);
 	show_space();
 
-	(void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
-	(void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Header length = %d", len);
-	(void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Routing type = %d", type);
-	(void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Segments left = %d", segleft);
 
 	if (type == IPV6_RTHDR_TYPE_0) {
@@ -774,14 +783,14 @@
 		 * XXX to differentiate between the hops yet to do
 		 * XXX and the hops already taken.
 		 */
+		/* LINTED: alignment */
 		ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr;
 		numaddrs = ipv6ext_rthdr0->ip6r0_len / 2;
 		addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1);
 		for (i = 0; i < numaddrs; i++) {
 			(void) inet_ntop(AF_INET6, &addrs[i], addr,
 			    INET6_ADDRSTRLEN);
-			(void) sprintf(get_line((char *)ipv6ext_rthdr -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "address[%d]=%s", i, addr);
 		}
 	}
@@ -790,9 +799,7 @@
 }
 
 static void
-prt_fragment_hdr(flags, ipv6ext_frag)
-	int flags;
-	struct ip6_frag *ipv6ext_frag;
+prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag)
 {
 	boolean_t morefrag;
 	uint16_t fragoffset;
@@ -807,7 +814,7 @@
 	fragident = ntohl(ipv6ext_frag->ip6f_ident);
 
 	if (flags & F_SUM) {
-		(void) sprintf(get_sum_line(),
+		(void) snprintf(get_sum_line(), MAXLINE,
 		    "IPv6 fragment ID=%d Offset=%-4d MF=%d",
 		    fragident,
 		    fragoffset,
@@ -816,13 +823,13 @@
 		show_header("IPv6-Frag:  ", "IPv6 Fragment Header", 0);
 		show_space();
 
-		(void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
-		(void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Fragment Offset = %d", fragoffset);
-		(void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "More Fragments Flag = %s", morefrag ? "true" : "false");
-		(void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 		    "Identification = %d", fragident);
 
 		show_space();
@@ -830,12 +837,131 @@
 }
 
 static void
-prt_hbh_options(flags, ipv6ext_hbh)
-	int flags;
-	struct ip6_hbh *ipv6ext_hbh;
+print_ip6opt_ls(const uchar_t *data, unsigned int op_len)
 {
-	uint8_t *data;
-	uint32_t len, olen;
+	uint32_t doi;
+	uint8_t sotype, solen;
+	uint16_t value, value2;
+	char *cp;
+	int remlen;
+	boolean_t printed;
+
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Labeled Security Option len = %u bytes%s", op_len,
+	    op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : "");
+	if (op_len < sizeof (uint32_t))
+		return;
+	GETINT32(doi, data);
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "    DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???");
+	op_len -= sizeof (uint32_t);
+	while (op_len > 0) {
+		GETINT8(sotype, data);
+		if (op_len < 2) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "    truncated %u suboption (no len)", sotype);
+			break;
+		}
+		GETINT8(solen, data);
+		if (solen < 2 || solen > op_len) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "    bad %u suboption (len 2 <= %u <= %u)",
+			    sotype, solen, op_len);
+			if (solen < 2)
+				solen = 2;
+			if (solen > op_len)
+				solen = op_len;
+		}
+		op_len -= solen;
+		solen -= 2;
+		cp = get_line(0, 0);
+		remlen = get_line_remain();
+		(void) strlcpy(cp, "    ", remlen);
+		cp += 4;
+		remlen -= 4;
+		printed = B_TRUE;
+		switch (sotype) {
+		case IP6LS_TT_LEVEL:
+			if (solen != 2) {
+				printed = B_FALSE;
+				break;
+			}
+			GETINT16(value, data);
+			(void) snprintf(cp, remlen, "Level %u", value);
+			solen = 0;
+			break;
+		case IP6LS_TT_VECTOR:
+			(void) strlcpy(cp, "Bit-Vector: ", remlen);
+			remlen -= strlen(cp);
+			cp += strlen(cp);
+			while (solen > 1) {
+				GETINT16(value, data);
+				solen -= 2;
+				(void) snprintf(cp, remlen, "%04x", value);
+				remlen -= strlen(cp);
+				cp += strlen(cp);
+			}
+			break;
+		case IP6LS_TT_ENUM:
+			(void) strlcpy(cp, "Enumeration:", remlen);
+			remlen -= strlen(cp);
+			cp += strlen(cp);
+			while (solen > 1) {
+				GETINT16(value, data);
+				solen -= 2;
+				(void) snprintf(cp, remlen, " %u", value);
+				remlen -= strlen(cp);
+				cp += strlen(cp);
+			}
+			break;
+		case IP6LS_TT_RANGES:
+			(void) strlcpy(cp, "Ranges:", remlen);
+			remlen -= strlen(cp);
+			cp += strlen(cp);
+			while (solen > 3) {
+				GETINT16(value, data);
+				GETINT16(value2, data);
+				solen -= 4;
+				(void) snprintf(cp, remlen, " %u-%u", value,
+				    value2);
+				remlen -= strlen(cp);
+				cp += strlen(cp);
+			}
+			break;
+		case IP6LS_TT_V4:
+			(void) strlcpy(cp, "IPv4 Option", remlen);
+			print_ipoptions(data, solen);
+			solen = 0;
+			break;
+		case IP6LS_TT_DEST:
+			(void) snprintf(cp, remlen,
+			    "Destination-Only Data length %u", solen);
+			solen = 0;
+			break;
+		default:
+			(void) snprintf(cp, remlen,
+			    "    unknown %u suboption (len %u)", sotype, solen);
+			solen = 0;
+			break;
+		}
+		if (solen != 0) {
+			if (printed) {
+				cp = get_line(0, 0);
+				remlen = get_line_remain();
+			}
+			(void) snprintf(cp, remlen,
+			    "    malformed %u suboption (remaining %u)",
+			    sotype, solen);
+			data += solen;
+		}
+	}
+}
+
+static void
+prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh)
+{
+	const uint8_t *data, *ndata;
+	uint32_t len;
 	uint8_t op_type;
 	uint8_t op_len;
 	uint8_t nxt_hdr;
@@ -854,85 +980,84 @@
 	 */
 	len = ipv6ext_hbh->ip6h_len * 8 + 8;
 
-	data = (uint8_t *)ipv6ext_hbh + 2;
+	ndata = (const uint8_t *)ipv6ext_hbh + 2;
 	len -= 2;
 
 	nxt_hdr = ipv6ext_hbh->ip6h_nxt;
-	(void) sprintf(get_line((char *)ipv6ext_hbh - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
 
 	while (len > 0) {
+		data = ndata;
 		GETINT8(op_type, data);
-		olen = len;
-		switch (op_type) {
-		case IP6OPT_PAD1:
-			(void) sprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1),
+		/* This is the only one-octet IPv6 option */
+		if (op_type == IP6OPT_PAD1) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "pad1 option ");
 			len--;
-			break;
+			ndata = data;
+			continue;
+		}
+		GETINT8(op_len, data);
+		if (len < 2 || op_len + 2 > len) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Error: option %u truncated (%u + 2 > %u)",
+			    op_type, op_len, len);
+			op_len = len - 2;
+			/*
+			 * Continue processing the malformed option so that we
+			 * can display as much as possible.
+			 */
+		}
+
+		/* advance pointers to the next option */
+		len -= op_len + 2;
+		ndata = data + op_len;
+
+		/* process this option */
+		switch (op_type) {
 		case IP6OPT_PADN:
-			GETINT8(op_len, data);
-			(void) sprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "padN option len = %u", op_len);
-			data += op_len;	/* skip pads */
-			len -= (op_len + 2);
 			break;
 		case IP6OPT_JUMBO: {
 			uint32_t payload_len;
 
-			GETINT8(op_len, data);
-			(void) sprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1),
-			    "Jumbo Payload Option len = %u bytes", op_len);
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Jumbo Payload Option len = %u bytes%s", op_len,
+			    op_len == sizeof (uint32_t) ? "" : "?");
 			if (op_len == sizeof (uint32_t)) {
 				GETINT32(payload_len, data);
-				(void) sprintf(get_line((char *)ipv6ext_hbh -
-				    dlc_header, 1),
+				(void) snprintf(get_line(0, 0),
+				    get_line_remain(),
 				    "Jumbo Payload Length = %u bytes",
 				    payload_len);
-			} else {
-				data += op_len;
 			}
-			len -= (op_len + 2);
 			break;
 		}
 		case IP6OPT_ROUTER_ALERT: {
 			uint16_t value;
 			const char *label[] = {"MLD", "RSVP", "AN"};
 
-			GETINT8(op_len, data);
-			(void) snprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1), get_line_remain(),
-			    "Router Alert Option len = %u bytes", op_len);
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Router Alert Option len = %u bytes%s", op_len,
+			    op_len == sizeof (uint16_t) ? "" : "?");
 			if (op_len == sizeof (uint16_t)) {
 				GETINT16(value, data);
-				(void) snprintf(get_line((char *)ipv6ext_hbh -
-				    dlc_header, 1), get_line_remain(),
+				(void) snprintf(get_line(0, 0),
+				    get_line_remain(),
 				    "Alert Type = %d (%s)", value,
 				    value < sizeof (label) / sizeof (label[0]) ?
 				    label[value] : "???");
-			} else {
-				data += op_len;
 			}
-			len -= (op_len + 2);
 			break;
 		}
+		case IP6OPT_LS:
+			print_ip6opt_ls(data, op_len);
+			break;
 		default:
-			GETINT8(op_len, data);
-			(void) sprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Option type = %u, len = %u", op_type, op_len);
-			data += op_len;
-			len -= (op_len + 2);
-		}
-		/* check for corrupt length */
-		if (olen <= len) {
-			(void) sprintf(get_line((char *)ipv6ext_hbh -
-			    dlc_header, 1),
-			    "Incomplete option len = %u, len = %u", op_type,
-			    len);
 			break;
 		}
 	}
@@ -941,12 +1066,10 @@
 }
 
 static void
-prt_dest_options(flags, ipv6ext_dest)
-	int flags;
-	struct ip6_dest *ipv6ext_dest;
+prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest)
 {
-	uint8_t *data;
-	uint32_t len, olen;
+	const uint8_t *data, *ndata;
+	uint32_t len;
 	uint8_t op_type;
 	uint32_t op_len;
 	uint8_t nxt_hdr;
@@ -966,57 +1089,405 @@
 	 */
 	len = ipv6ext_dest->ip6d_len * 8 + 8;
 
-	data = (uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */
+	ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */
 	len -= 2;
 
 	nxt_hdr = ipv6ext_dest->ip6d_nxt;
-	(void) sprintf(get_line((char *)ipv6ext_dest - dlc_header, 1),
+	(void) snprintf(get_line(0, 0), get_line_remain(),
 	    "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
 
 	while (len > 0) {
+		data = ndata;
 		GETINT8(op_type, data);
-		olen = len;
-		switch (op_type) {
-		case IP6OPT_PAD1:
-			(void) sprintf(get_line((char *)ipv6ext_dest -
-			    dlc_header, 1),
+		if (op_type == IP6OPT_PAD1) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "pad1 option ");
 			len--;
-			break;
+			ndata = data;
+			continue;
+		}
+		GETINT8(op_len, data);
+		if (len < 2 || op_len + 2 > len) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Error: option %u truncated (%u + 2 > %u)",
+			    op_type, op_len, len);
+			op_len = len - 2;
+			/*
+			 * Continue processing the malformed option so that we
+			 * can display as much as possible.
+			 */
+		}
+
+		/* advance pointers to the next option */
+		len -= op_len + 2;
+		ndata = data + op_len;
+
+		/* process this option */
+		switch (op_type) {
 		case IP6OPT_PADN:
-			GETINT8(op_len, data);
-			(void) sprintf(get_line((char *)ipv6ext_dest -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "padN option len = %u", op_len);
-			data += op_len;
-			len -= (op_len + 2);
 			break;
 		case IP6OPT_TUNNEL_LIMIT:
-			GETINT8(op_len, data);
 			GETINT8(value, data);
-			(void) sprintf(get_line((char *)ipv6ext_dest -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "tunnel encapsulation limit len = %d, value = %d",
 			    op_len, value);
-			len -= (op_len + 2);
+			break;
+		case IP6OPT_LS:
+			print_ip6opt_ls(data, op_len);
 			break;
 		default:
-			GETINT8(op_len, data);
-			(void) sprintf(get_line((char *)ipv6ext_dest -
-			    dlc_header, 1),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Option type = %u, len = %u", op_type, op_len);
-			data += op_len;
-			len -= (op_len + 2);
-		}
-		/* check for corrupt length */
-		if (olen <= len) {
-			(void) sprintf(get_line((char *)ipv6ext_dest -
-			    dlc_header, 1),
-			    "Incomplete option len = %u, len = %u", op_type,
-			    len);
 			break;
 		}
 	}
 
 	show_space();
 }
+
+#define	ALABEL_MAXLEN	256
+
+static char ascii_label[ALABEL_MAXLEN];
+static char *plabel = ascii_label;
+
+struct snoop_pair {
+	int val;
+	const char *name;
+};
+
+static struct snoop_pair ripso_class_tbl[] = {
+	TSOL_CL_TOP_SECRET,	"TOP SECRET",
+	TSOL_CL_SECRET,		"SECRET",
+	TSOL_CL_CONFIDENTIAL,	"CONFIDENTIAL",
+	TSOL_CL_UNCLASSIFIED,	"UNCLASSIFIED",
+	-1,			NULL
+};
+
+static struct snoop_pair ripso_prot_tbl[] = {
+	TSOL_PA_GENSER,		"GENSER",
+	TSOL_PA_SIOP_ESI,	"SIOP-ESI",
+	TSOL_PA_SCI,		"SCI",
+	TSOL_PA_NSA,		"NSA",
+	TSOL_PA_DOE,		"DOE",
+	0x04,			"UNASSIGNED",
+	0x02,			"UNASSIGNED",
+	-1,			NULL
+};
+
+static struct snoop_pair *
+get_pair_byval(struct snoop_pair pairlist[], int val)
+{
+	int i;
+
+	for (i = 0; pairlist[i].name != NULL; i++)
+		if (pairlist[i].val == val)
+			return (&pairlist[i]);
+	return (NULL);
+}
+
+static void
+print_ripso(const uchar_t *opt)
+{
+	struct snoop_pair *ripso_class;
+	int i, index, prot_len;
+	boolean_t first_prot;
+	char line[100], *ptr;
+
+	prot_len = opt[1] - 3;
+	if (prot_len < 0)
+		return;
+
+	show_header("RIPSO:  ", "Revised IP Security Option", 0);
+	show_space();
+
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]);
+
+	/*
+	 * Display Classification Level
+	 */
+	ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]);
+	if (ripso_class != NULL)
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Classification = Unknown (0x%02x)", opt[2]);
+	else
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Classification = %s (0x%02x)",
+		    ripso_class->name, ripso_class->val);
+
+	/*
+	 * Display Protection Authority Flags
+	 */
+	(void) snprintf(line, sizeof (line), "Protection Authority = ");
+	ptr = line;
+	first_prot = B_TRUE;
+	for (i = 0; i < prot_len; i++) {
+		index = 0;
+		while (ripso_prot_tbl[index].name != NULL) {
+			if (opt[3 + i] & ripso_prot_tbl[index].val) {
+				ptr = strchr(ptr, 0);
+				if (!first_prot) {
+					(void) strlcpy(ptr, ", ",
+					    sizeof (line) - (ptr - line));
+					ptr = strchr(ptr, 0);
+				}
+				(void) snprintf(ptr,
+				    sizeof (line) - (ptr - line),
+				    "%s (0x%02x)",
+				    ripso_prot_tbl[index].name,
+				    ripso_prot_tbl[index].val);
+			}
+			index++;
+		}
+		if ((opt[3 + i] & 1) == 0)
+			break;
+	}
+	if (!first_prot)
+		(void) snprintf(get_line(0, 0), get_line_remain(), "%s", line);
+	else
+		(void) snprintf(get_line(0, 0), get_line_remain(), "%sNone",
+		    line);
+}
+
+#define	CIPSO_GENERIC_ARRAY_LEN	200
+
+/*
+ * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise.
+ *
+ * Note: opt starts with "Tag Type":
+ *
+ * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
+ *
+ */
+static boolean_t
+cipso_high(const uchar_t *opt)
+{
+	int i;
+
+	if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH)
+		return (B_FALSE);
+	for (i = 0; i < ((int)opt[1] - 3); i++)
+		if (opt[3 + i] != 0xff)
+			return (B_FALSE);
+	return (B_TRUE);
+}
+
+/*
+ * Converts CIPSO label to SL.
+ *
+ * Note: opt starts with "Tag Type":
+ *
+ * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
+ *
+ */
+static void
+cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high)
+{
+	int i, taglen;
+	uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments;
+
+	*high = 0;
+	taglen = opt[1];
+	memset((caddr_t)sl, 0, sizeof (bslabel_t));
+
+	if (cipso_high(opt)) {
+		BSLHIGH(sl);
+		*high = 1;
+	} else {
+		LCLASS_SET((_bslabel_impl_t *)sl, opt[3]);
+		for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++)
+			q[i] = opt[TSOL_TT1_MIN_LENGTH + i];
+	}
+	SETBLTYPE(sl, SUN_SL_ID);
+}
+
+static int
+interpret_cipso_tagtype1(const uchar_t *opt)
+{
+	int i, taglen, ishigh;
+	bslabel_t sl;
+	char line[CIPSO_GENERIC_ARRAY_LEN], *ptr;
+
+	taglen = opt[1];
+	if (taglen < TSOL_TT1_MIN_LENGTH ||
+	    taglen > TSOL_TT1_MAX_LENGTH)
+		return (taglen);
+
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Tag Type = %d, Tag Length = %d", opt[0], opt[1]);
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Sensitivity Level = 0x%02x", opt[3]);
+	ptr = line;
+	for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) {
+		(void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x",
+		    opt[TSOL_TT1_MIN_LENGTH + i]);
+		ptr = strchr(ptr, 0);
+	}
+	if (i != 0) {
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Categories = ");
+		(void) snprintf(get_line(0, 0), get_line_remain(), "\t%s",
+		    line);
+	} else {
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Categories = None");
+	}
+	cipso2sl(opt, &sl, &ishigh);
+	if (is_system_labeled) {
+		if (bsltos(&sl, &plabel, ALABEL_MAXLEN,
+		    LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "The Sensitivity Level and Categories can't be "
+			    "mapped to a valid SL");
+		} else {
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "The Sensitivity Level and Categories are mapped "
+			    "to the SL:");
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "\t%s", ascii_label);
+		}
+	}
+	return (taglen);
+}
+
+/*
+ * The following struct definition #define's are copied from TS1.x. They are
+ * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for
+ * the tag type 3 packet format.
+ */
+#define	TTYPE_3_MAX_TOKENS	7
+
+/*
+ * Display CIPSO tag type 3 which is defined by MAXSIX.
+ */
+static int
+interpret_cipso_tagtype3(const uchar_t *opt)
+{
+	uchar_t tagtype;
+	int index, numtokens, taglen;
+	uint16_t mask;
+	uint32_t token;
+	static const char *name[] = {
+		"SL",
+		"NCAV",
+		"INTEG",
+		"SID",
+		"undefined",
+		"undefined",
+		"IL",
+		"PRIVS",
+		"LUID",
+		"PID",
+		"IDS",
+		"ACL"
+	};
+
+	tagtype = *opt++;
+	(void) memcpy(&mask, opt + 3, sizeof (mask));
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Tag Type = %d (MAXSIX)", tagtype);
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1],
+	    opt[2], mask);
+	opt += 3 + sizeof (mask);
+
+	/*
+	 * Display tokens
+	 */
+	numtokens = 0;
+	index = 0;
+	while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) {
+		if (mask & 0x0001) {
+			(void) memcpy(&token, opt, sizeof (token));
+			opt += sizeof (token);
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Attribute = %s, Token = 0x%08x",
+			    index < sizeof (name) / sizeof (*name) ?
+			    name[index] : "unknown", token);
+			numtokens++;
+		}
+		mask = mask >> 1;
+		index++;
+	}
+
+	taglen = 6 + numtokens * 4;
+	return (taglen);
+}
+
+static void
+print_cipso(const uchar_t *opt)
+{
+	int optlen, taglen, tagnum;
+	uint32_t doi;
+	char line[CIPSO_GENERIC_ARRAY_LEN];
+	char *oldnest;
+
+	optlen = opt[1];
+	if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH)
+		return;
+
+	oldnest = prot_nest_prefix;
+	prot_nest_prefix = prot_prefix;
+	show_header("CIPSO:  ", "Common IP Security Option", 0);
+	show_space();
+
+	/*
+	 * Display CIPSO Header
+	 */
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Type = CIPSO (%d), Length = %d", opt[0], opt[1]);
+	(void) memcpy(&doi, opt + 2, sizeof (doi));
+	(void) snprintf(get_line(0, 0), get_line_remain(),
+	    "Domain of Interpretation = %u", (unsigned)ntohl(doi));
+
+	if (opt[1] == TSOL_CIPSO_MIN_LENGTH) {	/* no tags */
+		show_space();
+		prot_prefix = prot_nest_prefix;
+		prot_nest_prefix = oldnest;
+		return;
+	}
+	optlen -= TSOL_CIPSO_MIN_LENGTH;
+	opt += TSOL_CIPSO_MIN_LENGTH;
+
+	/*
+	 * Display Each Tag
+	 */
+	tagnum = 1;
+	while (optlen >= TSOL_TT1_MIN_LENGTH) {
+		(void) snprintf(line, sizeof (line), "Tag# %d", tagnum);
+		show_header("CIPSO:  ", line, 0);
+		/*
+		 * We handle tag type 1 and 3 only. Note, tag type 3
+		 * is MAXSIX defined.
+		 */
+		switch (opt[0]) {
+		case 1:
+			taglen = interpret_cipso_tagtype1(opt);
+			break;
+		case 3:
+			taglen = interpret_cipso_tagtype3(opt);
+			break;
+		default:
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Unknown Tag Type %d", opt[0]);
+			show_space();
+			prot_prefix = prot_nest_prefix;
+			prot_nest_prefix = oldnest;
+			return;
+		}
+
+		/*
+		 * Move to the next tag
+		 */
+		if (taglen <= 0)
+			break;
+		optlen -= taglen;
+		opt += taglen;
+		tagnum++;
+	}
+	show_space();
+	prot_prefix = prot_nest_prefix;
+	prot_nest_prefix = oldnest;
+}
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,13 +19,14 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -40,8 +40,10 @@
 #include <string.h>
 #include <signal.h>
 #include <setjmp.h>
+#include <arpa/inet.h>
+#include "snoop.h"
 
-sigjmp_buf nisjmp;
+static sigjmp_buf nisjmp;
 
 #define	MAXHASH 1024  /* must be a power of 2 */
 
@@ -70,16 +72,16 @@
 	struct in6_addr	h6_addr;
 };
 
-static struct hostdata *addhost(int, void *, char *, char **);
+static struct hostdata *addhost(int, const void *, const char *, char **);
 
-struct hostdata4 *h_table4[MAXHASH];
-struct hostdata6 *h_table6[MAXHASH];
+static struct hostdata4 *h_table4[MAXHASH];
+static struct hostdata6 *h_table6[MAXHASH];
 
 #define	iphash(e)  ((e) & (MAXHASH-1))
 
+/* ARGSUSED */
 static void
-wakeup(n)
-	int n;
+wakeup(int n)
 {
 	siglongjmp(nisjmp, 1);
 }
@@ -135,7 +137,7 @@
 }
 
 static struct hostdata *
-ip6lookup(struct in6_addr *ip6addr)
+ip6lookup(const struct in6_addr *ip6addr)
 {
 	struct hostdata6 *h;
 	struct hostent *hp = NULL;
@@ -182,9 +184,9 @@
 }
 
 static struct hostdata *
-addhost(int family, void *ipaddr, char *name, char **aliases)
+addhost(int family, const void *ipaddr, const char *name, char **aliases)
 {
-	register struct hostdata **hp, *n = NULL;
+	struct hostdata **hp, *n = NULL;
 	extern FILE *namefile;
 	int hashval;
 	static char aname[128];
@@ -203,7 +205,8 @@
 		if (n->h_hostname == NULL)
 			goto alloc_failed;
 
-		((struct hostdata4 *)n)->h4_addr = *(struct in_addr *)ipaddr;
+		((struct hostdata4 *)n)->h4_addr =
+		    *(const struct in_addr *)ipaddr;
 		hashval = ((struct in_addr *)ipaddr)->s_addr;
 		hp = (struct hostdata **)&h_table4[iphash(hashval)];
 		break;
@@ -219,7 +222,7 @@
 
 		memcpy(&((struct hostdata6 *)n)->h6_addr, ipaddr,
 		    sizeof (struct in6_addr));
-		hashval = ((int *)ipaddr)[3];
+		hashval = ((const int *)ipaddr)[3];
 		hp = (struct hostdata **)&h_table6[iphash(hashval)];
 		break;
 	default:
@@ -233,7 +236,7 @@
 
 	if (namefile != NULL) {
 		if (family == AF_INET) {
-			np = inet_ntoa(*(struct in_addr *)ipaddr);
+			np = inet_ntoa(*(const struct in_addr *)ipaddr);
 			if (np) {
 				(void) fprintf(namefile, "%s\t%s", np, name);
 				if (aliases) {
@@ -280,22 +283,18 @@
 }
 
 char *
-addrtoname(family, ipaddr)
-	int family;
-	void *ipaddr;
+addrtoname(int family, const void *ipaddr)
 {
 	switch (family) {
 	case AF_INET:
-		return (iplookup(*(struct in_addr *)ipaddr)->h_hostname);
+		return (iplookup(*(const struct in_addr *)ipaddr)->h_hostname);
 	case AF_INET6:
-		return (ip6lookup((struct in6_addr *)ipaddr)->h_hostname);
-	default:
-		fprintf(stderr, "snoop: ERROR: unknown address family: %d\n",
-		    family);
-		exit(1);
+		return (ip6lookup((const struct in6_addr *)ipaddr)->h_hostname);
 	}
-	/* Never reached... */
-	return (NULL);
+	(void) fprintf(stderr, "snoop: ERROR: unknown address family: %d\n",
+	    family);
+	exit(1);
+	/* NOTREACHED */
 }
 
 void
@@ -324,14 +323,15 @@
 		if (inet_pton(AF_INET6, addr, (void *)&addrv6) == 1) {
 			family = AF_INET6;
 			naddr = (void *)&addrv6;
-		} else if ((addrv4 = inet_addr(addr)) != -1) {
+		} else if ((addrv4 = inet_addr(addr)) != (ulong_t)-1) {
 			family = AF_INET;
 			naddr = (void *)&addrv4;
 		}
 		name = strtok(NULL, SEPARATORS);
 		if (name == NULL)
 			continue;
-		while ((alias = strtok(NULL, SEPARATORS)) && (*alias != '#')) {
+		while ((alias = strtok(NULL, SEPARATORS)) != NULL &&
+		    (*alias != '#')) {
 			(void) addhost(family, naddr, alias, NULL);
 		}
 		(void) addhost(family, naddr, name, NULL);
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +31,7 @@
 #include <string.h>
 #include <fcntl.h>
 #include <string.h>
+#include <strings.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 #include <sys/time.h>
@@ -49,11 +49,11 @@
 #include <inet/ipsecah.h>
 #include "snoop.h"
 
-extern char *dlc_header;
-
+/* ARGSUSED */
 int
 interpret_esp(int flags, uint8_t *hdr, int iplen, int fraglen)
 {
+	/* LINTED: alignment */
 	esph_t *esph = (esph_t *)hdr;
 	esph_t *aligned_esph;
 	esph_t storage;	/* In case hdr isn't aligned. */
@@ -104,6 +104,7 @@
 int
 interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen)
 {
+	/* LINTED: alignment */
 	ah_t *ah = (ah_t *)hdr;
 	ah_t *aligned_ah;
 	ah_t storage;	/* In case hdr isn't aligned. */
@@ -118,7 +119,7 @@
 
 	if (!IS_P2ALIGNED(hdr, 4)) {
 		aligned_ah = (ah_t *)&storage;
-		bcopy(hdr, storage, sizeof (ah_t));
+		bcopy(hdr, &storage, sizeof (ah_t));
 	} else {
 		aligned_ah = ah;
 	}
@@ -197,6 +198,7 @@
 	if (fraglen > 0)
 		switch (proto) {
 			case IPPROTO_ENCAP:
+				/* LINTED: alignment */
 				(void) interpret_ip(flags, (struct ip *)data,
 				    new_iplen);
 				break;
@@ -205,27 +207,33 @@
 				    new_iplen);
 				break;
 			case IPPROTO_ICMP:
-				interpret_icmp(flags, (struct icmp *)data,
-				    new_iplen, fraglen);
+				(void) interpret_icmp(flags,
+				    /* LINTED: alignment */
+				    (struct icmp *)data, new_iplen, fraglen);
 				break;
 			case IPPROTO_ICMPV6:
-				interpret_icmpv6(flags, (icmp6_t *)data,
+				/* LINTED: alignment */
+				(void) interpret_icmpv6(flags, (icmp6_t *)data,
 				    new_iplen, fraglen);
 				break;
 			case IPPROTO_TCP:
-				interpret_tcp(flags, data, new_iplen, fraglen);
+				(void) interpret_tcp(flags,
+				    (struct tcphdr *)data, new_iplen, fraglen);
 				break;
 
 			case IPPROTO_ESP:
-				interpret_esp(flags, data, new_iplen, fraglen);
-				break;
-			case IPPROTO_AH:
-				interpret_ah(flags, data, new_iplen, fraglen);
+				(void) interpret_esp(flags, data, new_iplen,
+				    fraglen);
 				break;
 
+			case IPPROTO_AH:
+				(void) interpret_ah(flags, data, new_iplen,
+				    fraglen);
+				break;
 
 			case IPPROTO_UDP:
-				interpret_udp(flags, data, new_iplen, fraglen);
+				(void) interpret_udp(flags,
+				    (struct udphdr *)data, new_iplen, fraglen);
 				break;
 			/* default case is to not print anything else */
 		}
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,7 +37,10 @@
 #include <protocols/routed.h>
 #include "snoop.h"
 
-static char *show_cmd(int);
+static const char *show_cmd(int);
+static int get_numtokens(unsigned int);
+static const struct rip_sec_entry *rip_next_sec_entry(
+    const struct rip_sec_entry *, int);
 
 int
 interpret_rip(int flags, struct rip *rip, int fraglen)
@@ -46,6 +48,9 @@
 	const struct netinfo *nip;
 	const struct entryinfo *ep;
 	const struct netauth *nap;
+	const struct rip_sec_entry *rsep, *rsn;
+	const struct rip_emetric *rep;
+	const uint32_t *tokp;
 	int len, count;
 	const char *cmdstr, *auth;
 	struct in_addr dst;
@@ -68,6 +73,8 @@
 		case RIPCMD_TRACEOFF:	cmdstr = "Traceoff";	break;
 		case RIPCMD_POLL:	cmdstr = "Poll";	break;
 		case RIPCMD_POLLENTRY:	cmdstr = "Poll entry";	break;
+		case RIPCMD_SEC_RESPONSE: cmdstr = "R - SEC";	break;
+		case RIPCMD_SEC_T_RESPONSE: cmdstr = "R - SEC_T"; break;
 		default: cmdstr = "?"; break;
 		}
 
@@ -108,6 +115,26 @@
 			len = 0;
 			break;
 
+		case RIPCMD_SEC_RESPONSE:
+		case RIPCMD_SEC_T_RESPONSE:
+			if (len < sizeof (rip->rip_tsol.rip_generation))
+				break;
+			len -= sizeof (rip->rip_tsol.rip_generation);
+			count = 0;
+			rsep = rip->rip_tsol.rip_sec_entry;
+			while (len > 0) {
+				rsn = rip_next_sec_entry(rsep, len);
+				if (rsn == NULL)
+					break;
+				len -= (const char *)rsn - (const char *)rsep;
+				rsep = rsn;
+				count++;
+			}
+			(void) snprintf(get_sum_line(), MAXLINE,
+			    "%s %s (%d destinations%s)", ripvers, cmdstr,
+			    count, (len != 0 ? "?" : ""));
+			break;
+
 		default:
 			(void) snprintf(get_sum_line(), MAXLINE,
 			    "%s %d (%s)", ripvers, rip->rip_cmd, cmdstr);
@@ -121,12 +148,11 @@
 		len = fraglen - 4;
 		show_header("RIP:  ", "Routing Information Protocol", fraglen);
 		show_space();
-		(void) snprintf(get_line((char *)(uintptr_t)rip->rip_cmd -
-		    dlc_header, 1), get_line_remain(), "Opcode = %d (%s)",
-		    rip->rip_cmd, show_cmd(rip->rip_cmd));
-		(void) snprintf(get_line((char *)(uintptr_t)rip->rip_vers -
-		    dlc_header, 1), get_line_remain(), "Version = %d",
-		    rip->rip_vers);
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Opcode = %d (%s)", rip->rip_cmd,
+		    show_cmd(rip->rip_cmd));
+		(void) snprintf(get_line(0, 0), get_line_remain(),
+		    "Version = %d", rip->rip_vers);
 
 		switch (rip->rip_cmd) {
 		case RIPCMD_REQUEST:
@@ -156,9 +182,7 @@
 						    nap->au.au_pw);
 					} else if (nap->a_type ==
 					    RIP_AUTH_MD5) {
-						(void) snprintf(get_line
-						    ((char *)nip - dlc_header,
-							sizeof (*nip)),
+						(void) snprintf(get_line(0, 0),
 						    get_line_remain(),
 						    " *** Auth MD5 pkt len %d, "
 						    "keyid %d, sequence %08lX, "
@@ -166,7 +190,7 @@
 						    ntohs(nap->au.a_md5.
 							md5_pkt_len),
 						    nap->au.a_md5.md5_keyid,
-						    ntohl(nap->au.a_md5.
+						    (long)ntohl(nap->au.a_md5.
 							md5_seqno),
 						    ntohs(nap->au.a_md5.
 							md5_auth_len));
@@ -189,15 +213,13 @@
 				}
 				if (nip->n_family == RIP_AF_UNSPEC &&
 				    rip->rip_cmd == RIPCMD_REQUEST) {
-					(void) snprintf(get_line((char *)nip -
-					    dlc_header, sizeof (*nip)),
+					(void) snprintf(get_line(0, 0),
 					    get_line_remain(),
 					    " *** All routes");
 					continue;
 				}
 				if (nip->n_family != RIP_AF_INET) {
-					(void) snprintf(get_line((char *)nip -
-					    dlc_header, sizeof (*nip)),
+					(void) snprintf(get_line(0, 0),
 					    get_line_remain(),
 					    " *** Address Family %d?",
 					    ntohs(nip->n_family));
@@ -231,8 +253,7 @@
 				}
 				dst.s_addr = nip->n_nhop;
 				mval = ntohl(nip->n_metric);
-				(void) snprintf(get_line((char *)nip -
-				    dlc_header, sizeof (*nip)),
+				(void) snprintf(get_line(0, 0),
 				    get_line_remain(),
 				    "%-31s %-15s %-6d %d%s",
 				    addrstr,
@@ -252,44 +273,105 @@
 			ep = (const struct entryinfo *)rip->rip_nets;
 			/* LINTED */
 			sin = (const struct sockaddr_in *)&ep->rtu_dst;
-			(void) snprintf(get_line((char *)sin - dlc_header,
-			    sizeof (struct sockaddr)), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Destination = %s %s",
 			    inet_ntoa(sin->sin_addr),
 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
 			/* LINTED */
 			sin = (const struct sockaddr_in *)&ep->rtu_router;
-			(void) snprintf(get_line((char *)sin - dlc_header,
-			    sizeof (struct sockaddr)), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Router      = %s %s",
 			    inet_ntoa(sin->sin_addr),
 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
-			(void) snprintf(get_line((char *)&ep->rtu_flags -
-			    dlc_header, 2), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Flags = %4x", (unsigned)ep->rtu_flags);
-			(void) snprintf(get_line((char *)&ep->rtu_state -
-			    dlc_header, 2), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "State = %d", ep->rtu_state);
-			(void) snprintf(get_line((char *)&ep->rtu_timer -
-			    dlc_header, 4), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Timer = %d", ep->rtu_timer);
-			(void) snprintf(get_line((char *)&ep->rtu_metric -
-			    dlc_header, 4), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Metric = %d", ep->rtu_metric);
-			(void) snprintf(get_line((char *)&ep->int_flags -
-			    dlc_header, 4), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Int flags = %8x", ep->int_flags);
-			(void) snprintf(get_line((char *)ep->int_name -
-			    dlc_header, sizeof (ep->int_name)),
-			    get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Int name = \"%.*s\"", sizeof (ep->int_name),
 			    ep->int_name);
 			break;
 
+		case RIPCMD_SEC_RESPONSE:
+		case RIPCMD_SEC_T_RESPONSE:
+			if (len < sizeof (rip->rip_tsol.rip_generation))
+				break;
+			len -= sizeof (rip->rip_tsol.rip_generation);
+			show_space();
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Generation = %u",
+			    (unsigned)ntohl(rip->rip_tsol.rip_generation));
+			rsep = rip->rip_tsol.rip_sec_entry;
+			(void) snprintf(get_line(0, 0), get_line_remain(),
+			    "Address         E-METRIC");
+			rsep = rip->rip_tsol.rip_sec_entry;
+			while (len > 0) {
+				char *cp;
+				int blen, num;
+
+				rsn = rip_next_sec_entry(rsep, len);
+				if (rsn == NULL)
+					break;
+				dst.s_addr = rsep->rip_dst;
+				cp = get_line(0, 0);
+				blen = get_line_remain();
+				(void) snprintf(cp, blen, "%-16s ",
+				    inet_ntoa(dst));
+				cp += 17;
+				blen -= 17;
+				rep = rsep->rip_emetric;
+				for (count = ntohl(rsep->rip_count); count > 0;
+				    count--) {
+					(void) snprintf(cp, blen, "metric=%d",
+					    ntohs(rep->rip_metric));
+					blen -= strlen(cp);
+					cp += strlen(cp);
+					tokp = rep->rip_token;
+					num = get_numtokens(
+					    ntohs(rep->rip_mask));
+					/* advance to the next emetric */
+					rep = (const struct rip_emetric *)
+					    &rep->rip_token[num];
+					if (num > 0) {
+						(void) snprintf(cp, blen,
+						    ",tokens=%lx",
+						    (long)ntohl(*tokp));
+						tokp++;
+						num--;
+					} else {
+						(void) strlcpy(cp, ",no tokens",
+						    blen);
+					}
+					while (num > 0) {
+						blen -= strlen(cp);
+						cp += strlen(cp);
+						(void) snprintf(cp, blen,
+						    ",%lx",
+						    (long)ntohl(*tokp));
+						tokp++;
+						num--;
+					}
+					blen -= strlen(cp);
+					cp += strlen(cp);
+				}
+				if (rsep->rip_count == 0) {
+					(void) strlcpy(cp,
+					    "NULL (not reachable)", blen);
+				}
+				len -= (const char *)rsn - (const char *)rsep;
+				rsep = rsn;
+			}
+			break;
+
 		case RIPCMD_TRACEON:
 		case RIPCMD_TRACEOFF:
-			(void) snprintf(get_line((char *)rip->rip_tracefile -
-			    dlc_header, 2), get_line_remain(),
+			(void) snprintf(get_line(0, 0), get_line_remain(),
 			    "Trace file = %.*s", len, rip->rip_tracefile);
 			len = 0;
 			break;
@@ -299,7 +381,7 @@
 	return (fraglen - len);
 }
 
-static char *
+static const char *
 show_cmd(int c)
 {
 	switch (c) {
@@ -315,6 +397,44 @@
 		return ("route poll");
 	case RIPCMD_POLLENTRY:
 		return ("route poll entry");
+	case RIPCMD_SEC_RESPONSE:
+		return ("route sec response");
+	case RIPCMD_SEC_T_RESPONSE:
+		return ("route sec_t response");
 	}
 	return ("?");
 }
+
+static int
+get_numtokens(unsigned int mask)
+{
+	int num = 0;
+
+	while (mask != 0) {
+		num++;
+		mask &= mask - 1;
+	}
+	return (num);
+}
+
+static const struct rip_sec_entry *
+rip_next_sec_entry(const struct rip_sec_entry *rsep, int len)
+{
+	const struct rip_emetric *rep;
+	const char *limit = (const char *)rsep + len;
+	long count;
+
+	if ((const char *)(rep = rsep->rip_emetric) > limit)
+		return (NULL);
+	count = ntohl(rsep->rip_count);
+	while (count > 0) {
+		if ((const char *)rep->rip_token > limit)
+			return (NULL);
+		rep = (struct rip_emetric *)
+		    &rep->rip_token[get_numtokens(ntohs(rep->rip_mask))];
+		if ((const char *)rep > limit)
+			return (NULL);
+		count--;
+	}
+	return ((const struct rip_sec_entry *)rep);
+}
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,14 +19,17 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <ctype.h>
+#include <strings.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/errno.h>
@@ -40,114 +42,106 @@
 #include <netinet/if_ether.h>
 #include "snoop.h"
 
-#define	NULL 0
-
-extern void interpret_mip_cntrlmsg(int, uchar_t *, int);
-
 struct porttable {
 	int	pt_num;
 	char	*pt_short;
-	char	*pt_long;
 };
 
-struct porttable pt_udp[] = {
-	7,	"ECHO",		"Echo",
-	9,	"DISCARD",	"Discard",
-	13,	"DAYTIME",	"Daytime",
-	19,	"CHARGEN",	"Character generator",
-	37,	"TIME",		"Time",
-	42,	"NAME",		"Host name server",
-	53,	"DNS",		"Domain Name Server",
-	67,	"BOOTPS",	"Bootstrap Protocol Server",
-	68,	"BOOTPC",	"Boostrap Protocol Client",
-	69,	"TFTP",		"Trivial File Transfer Protocol",
-	79,	"FINGER",	"Finger",
-/*	111,	"PORTMAP",	"Portmapper", Just Sun RPC */
-	123,	"NTP",		"Network Time Protocol",
-	137,	"NBNS",		"Netbios name service",
-	138,	"NBDG",		"Netbios datagram service",
-	389,	"LDAP",		"Lightweight Directory Access Protocol",
-	427,	"SLP",		"Service Location Protocol",
+static const struct porttable pt_udp[] = {
+	{ IPPORT_ECHO,		"ECHO" },
+	{ IPPORT_DISCARD,	"DISCARD" },
+	{ IPPORT_DAYTIME,	"DAYTIME" },
+	{ 19,			"CHARGEN" },
+	{ IPPORT_TIMESERVER,	"TIME" },
+	{ IPPORT_NAMESERVER,	"NAME" },
+	{ 53,			"DNS" },
+	{ IPPORT_BOOTPS,	"BOOTPS" },
+	{ IPPORT_BOOTPC,	"BOOTPC" },
+	{ IPPORT_TFTP,		"TFTP" },
+	{ IPPORT_FINGER,	"FINGER" },
+/*	{ 111,			"PORTMAP" }, Just Sun RPC */
+	{ 123,			"NTP" },
+	{ 137,			"NBNS" },
+	{ 138,			"NBDG" },
+	{ 389,			"LDAP" },
+	{ 427,			"SLP" },
 /* Mobile IP defines a set of new control messages sent over UDP port 434 */
-	434,	"Mobile IP",	"Mobile IP Control Messages",
-	512,	"BIFF",		"BIFF",
-	513,	"WHO",		"WHO",
-	514,	"SYSLOG",	"SYSLOG",
-	517,	"TALK",		"TALK",
-	520,	"RIP",		"Routing Information Protocol",
-	550,	"NEW-RWHO",	"NEW-RWHO",
-	560,	"RMONITOR",	"RMONITOR",
-	561,	"MONITOR",	"MONITOR",
-	521,	"RIPng",	"Routing Information Protocol for IPv6",
-	1080,	"SOCKS",	"SOCKS Gateway",
-	0,	NULL,		"",
+	{ 434,			"Mobile IP" },
+	{ IPPORT_BIFFUDP,	"BIFF" },
+	{ IPPORT_WHOSERVER,	"WHO" },
+	{ 514,			"SYSLOG" },
+	{ 517,			"TALK" },
+	{ IPPORT_ROUTESERVER,	"RIP" },
+	{ 521,			"RIPng" },
+	{ 550,			"NEW-RWHO" },
+	{ 560,			"RMONITOR" },
+	{ 561,			"MONITOR" },
+	{ 1080,			"SOCKS" },
+	{ 0,			NULL }
 };
 
-struct porttable pt_tcp[] = {
-	1,	"TCPMUX",	"TCPMUX",
-	7,	"ECHO",		"Echo",
-	9,	"DISCARD",	"Discard",
-	11,	"SYSTAT",	"Active users",
-	13,	"DAYTIME",	"Daytime",
-	15,	"NETSTAT",	"Who is up",
-	19,	"CHARGEN",	"Character generator",
-	20,	"FTP-DATA",	"File Transfer Protocol (data)",
-	21,	"FTP",		"File Transfer Protocol",
-	23,	"TELNET",	"Terminal connection",
-	25,	"SMTP",		"Simple Mail Transport Protocol",
-	37,	"TIME",		"Time",
-	39,	"RLP",		"Resource Location Protocol",
-	42,	"NAMESERVER",	"Host Name Server",
-	43,	"NICNAME",	"Who is",
-	53,	"DNS",		"Domain Name Server",
-	67,	"BOOTPS",	"Bootstrap Protocol Server",
-	68,	"BOOTPC",	"Bootstrap Protocol Client",
-	69,	"TFTP",		"Trivial File Transfer Protocol",
-	70,	"GOPHER",	"Internet Gopher Protocol",
-	77,	"RJE",		"RJE service (private)",
-	79,	"FINGER",	"Finger",
-	80,	"HTTP",		"HyperText Transfer Protocol",
-	87,	"LINK",		"Link",
-	95,	"SUPDUP",	"SUPDUP Protocol",
-	101,	"HOSTNAME",	"NIC Host Name Server",
-	102,	"ISO-TSAP",	"ISO-TSAP",
-	103,	"X400",		"X400 Mail service",
-	104,	"X400-SND",	"X400 Mail service",
-	105,	"CSNET-NS",	"CSNET-NS",
-	109,	"POP-2",	"POP-2",
-/*	111,	"PORTMAP",	"Portmapper", Just Sun RPC */
-	113,	"AUTH",		"Authentication Service",
-	117,	"UUCP-PATH",	"UUCP Path Service",
-	119,	"NNTP",		"Network News Transfer Protocol",
-	123,	"NTP",		"Network Time Protocol",
-	139,	"NBT",		"Netbios over TCP",
-	143,	"IMAP",		"Internet Message Access Protocol",
-	144,	"NeWS",		"Network extensible Window System",
-	389,	"LDAP",		"Lightweight Directory Access Protocol",
-	427,	"SLP",		"Service Location Protocol",
-	443,	"HTTPS",	"HTTP over SSL",
-	445,    "SMB",          "Direct Hosted Server Message Block",
-	512,	"EXEC",		"EXEC",
-	513,	"RLOGIN",	"RLOGIN",
-	514,	"RSHELL",	"RSHELL",
-	515,	"PRINTER",	"PRINTER",
-	530,	"COURIER",	"COURIER",
-	540,	"UUCP",		"UUCP",
-	600,	"PCSERVER",	"PCSERVER",
-	1524,	"INGRESLOCK",	"INGRESLOCK",
-	1080,	"SOCKS",	"SOCKS Gateway",
-	2904,	"M2UA",		"SS7 MTP2 User Adaption Layer",
-	2905,	"M3UA",		"SS7 MTP3 User Adaption Layer",
-	6000,	"XWIN",		"X Window System",
-	8080,	"HTTP (proxy)",	"HyperText Transfer Protocol (proxy)",
-	9900,	"IUA",		"ISDN Q.921 User Adaption Layer",
-	0,	NULL,		"",
+static struct porttable pt_tcp[] = {
+	{ 1,			"TCPMUX" },
+	{ IPPORT_ECHO,		"ECHO" },
+	{ IPPORT_DISCARD,	"DISCARD" },
+	{ IPPORT_SYSTAT,	"SYSTAT" },
+	{ IPPORT_DAYTIME,	"DAYTIME" },
+	{ IPPORT_NETSTAT,	"NETSTAT" },
+	{ 19,			"CHARGEN" },
+	{ 20,			"FTP-DATA" },
+	{ IPPORT_FTP,		"FTP" },
+	{ IPPORT_TELNET,	"TELNET" },
+	{ IPPORT_SMTP,		"SMTP" },
+	{ IPPORT_TIMESERVER,	"TIME" },
+	{ 39,			"RLP" },
+	{ IPPORT_NAMESERVER,	"NAMESERVER" },
+	{ IPPORT_WHOIS,		"NICNAME" },
+	{ 53,			"DNS" },
+	{ 70,			"GOPHER" },
+	{ IPPORT_RJE,		"RJE" },
+	{ IPPORT_FINGER,	"FINGER" },
+	{ 80,			"HTTP" },
+	{ IPPORT_TTYLINK,	"LINK" },
+	{ IPPORT_SUPDUP,	"SUPDUP" },
+	{ 101,			"HOSTNAME" },
+	{ 102,			"ISO-TSAP" },
+	{ 103,			"X400" },
+	{ 104,			"X400-SND" },
+	{ 105,			"CSNET-NS" },
+	{ 109,			"POP-2" },
+/*	{ 111,			"PORTMAP" }, Just Sun RPC */
+	{ 113,			"AUTH" },
+	{ 117,			"UUCP-PATH" },
+	{ 119,			"NNTP" },
+	{ 123,			"NTP" },
+	{ 139,			"NBT" },
+	{ 143,			"IMAP" },
+	{ 144,			"NeWS" },
+	{ 389,			"LDAP" },
+	{ 427,			"SLP" },
+	{ 443,			"HTTPS" },
+	{ 445,			"SMB" },
+	{ IPPORT_EXECSERVER,	"EXEC" },
+	{ IPPORT_LOGINSERVER,	"RLOGIN" },
+	{ IPPORT_CMDSERVER,	"RSHELL" },
+	{ 515,			"PRINTER" },
+	{ 530,			"COURIER" },
+	{ 540,			"UUCP" },
+	{ 600,			"PCSERVER" },
+	{ 1080,			"SOCKS" },
+	{ 1524,			"INGRESLOCK" },
+	{ 2904,			"M2UA" },
+	{ 2905,			"M3UA" },
+	{ 6000,			"XWIN" },
+	{ 8080,			"HTTP (proxy)" },
+	{ 9900,			"IUA" },
+	{ 0,			NULL },
 };
 
 char *
 getportname(int proto, in_port_t port)
 {
-	struct porttable *p, *pt;
+	const struct porttable *p, *pt;
 
 	switch (proto) {
 	case IPPROTO_SCTP: /* fallthru */
@@ -166,7 +160,7 @@
 int
 reservedport(int proto, int port)
 {
-	struct porttable *p, *pt;
+	const struct porttable *p, *pt;
 
 	switch (proto) {
 	case IPPROTO_TCP: pt = pt_tcp; break;
@@ -186,13 +180,13 @@
  * See TFTP interpreter.
  */
 #define	MAXTRANS 64
-struct ttable {
+static struct ttable {
 	int t_port;
-	int (*t_proc)();
+	int (*t_proc)(int, char *, int);
 } transients [MAXTRANS];
 
 int
-add_transient(int port, int (*proc)())
+add_transient(int port, int (*proc)(int, char *, int))
 {
 	static struct ttable *next = transients;
 
@@ -266,7 +260,7 @@
 			data++;
 			datalen--;
 
-			strlcpy(buffer, data, sizeof (buffer));
+			(void) strlcpy(buffer, data, sizeof (buffer));
 			composit = strtoul(buffer, &end, 0);
 			data += end - buffer;
 			if (*data == '>') {
@@ -306,11 +300,11 @@
 		static char syslog[] = "SYSLOG:  ";
 		show_header(syslog, syslog, dlen);
 		show_space();
-		(void) sprintf(get_detail_line(0, 80),
+		(void) snprintf(get_detail_line(0, 0), MAXLINE,
 		    "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
 		    priostrlen, syslogstr, bogus ? "" : " ",
 		    facilstr, pristr);
-		(void) sprintf(get_line(0, 0),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 			"\"%s\"",
 			show_string(syslogstr, dlen, 60));
 		show_trailer();
@@ -323,7 +317,7 @@
 interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
     char *data, int dlen)
 {
-	char *pn;
+	const char *pn;
 	int dir, port, which;
 	char pbuff[16], hbuff[32];
 	struct ttable *ttabp;
@@ -373,25 +367,29 @@
 
 	if (dlen > 0) {
 		switch (which) {
-		case  67:
-		case  68:
-			interpret_dhcp(flags, data, dlen);
+		case  IPPORT_BOOTPS:
+		case  IPPORT_BOOTPC:
+			(void) interpret_dhcp(flags, (struct dhcp *)data,
+			    dlen);
 			return (1);
-		case  69:
-			interpret_tftp(flags, data, dlen);
+		case  IPPORT_TFTP:
+			(void) interpret_tftp(flags, (struct tftphdr *)data,
+			    dlen);
 			return (1);
 		case  80:
 		case  8080:
-			interpret_http(flags, data, dlen);
+			(void) interpret_http(flags, data, dlen);
 			return (1);
 		case 123:
-			interpret_ntp(flags, data, dlen);
+			(void) interpret_ntp(flags, (struct ntpdata *)data,
+			    dlen);
 			return (1);
 		case 137:
-			interpret_netbios_ns(flags, data, dlen);
+			interpret_netbios_ns(flags, (uchar_t *)data, dlen);
 			return (1);
 		case 138:
-			interpret_netbios_datagram(flags, data, dlen);
+			interpret_netbios_datagram(flags, (uchar_t *)data,
+			    dlen);
 			return (1);
 		case 139:
 		case 445:
@@ -400,7 +398,7 @@
 			 * on port 139.  The same interpreter can be used
 			 * for both.
 			 */
-			interpret_netbios_ses(flags, data, dlen);
+			interpret_netbios_ses(flags, (uchar_t *)data, dlen);
 			return (1);
 		case 389:
 			interpret_ldap(flags, data, dlen, src, dst);
@@ -411,34 +409,36 @@
 		case 434:
 			interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
 			return (1);
-		case 520:
-			interpret_rip(flags, data, dlen);
+		case IPPORT_ROUTESERVER:
+			(void) interpret_rip(flags, (struct rip *)data, dlen);
 			return (1);
 		case 521:
-			interpret_rip6(flags, data, dlen);
+			(void) interpret_rip6(flags, (struct rip6 *)data,
+			    dlen);
 			return (1);
 		case 1080:
 			if (dir == 'C')
-				interpret_socks_call(flags, data, dlen);
+				(void) interpret_socks_call(flags, data, dlen);
 			else
-				interpret_socks_reply(flags, data, dlen);
+				(void) interpret_socks_reply(flags, data,
+				    dlen);
 			return (1);
 		}
 	}
 
 	if (flags & F_SUM) {
-		(void) sprintf(get_sum_line(),
+		(void) snprintf(get_sum_line(), MAXLINE,
 			"%s %c port=%d %s",
 			pn, dir, port,
 			show_string(data, dlen, 20));
 	}
 
 	if (flags & F_DTAIL) {
-		(void) sprintf(pbuff, "%s:  ", pn);
-		(void) sprintf(hbuff, "%s:  ", pn);
+		(void) snprintf(pbuff, sizeof (pbuff), "%s:  ", pn);
+		(void) snprintf(hbuff, sizeof (hbuff), "%s:  ", pn);
 		show_header(pbuff, hbuff, dlen);
 		show_space();
-		(void) sprintf(get_line(0, 0),
+		(void) snprintf(get_line(0, 0), get_line_remain(),
 			"\"%s\"",
 			show_string(data, dlen, 60));
 		show_trailer();
@@ -479,7 +479,7 @@
 				*pp++ = c;
 				printable++;
 			} else {
-				(void) sprintf(pp,
+				(void) snprintf(pp, TBSIZE - (pp - tbuff),
 					isdigit(*(p + 1)) ?
 					"\\%03o" : "\\%o", c);
 				pp += strlen(pp);
--- a/usr/src/cmd/devfsadm/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -32,12 +32,15 @@
 
 DEVFSADM_MOD = devfsadm
 
+DEVALLOCSRC =	devalloc.c
+
 PLCYSRC = devpolicy.c plcysubr.c
 
 MODLOADDIR = $(COMMON)/../modload
 
-DEVFSADM_SRC = $(COMMON)/$(DEVFSADM_MOD:%=%.c) $(PLCYSRC:%=$(COMMON)/%)
-DEVFSADM_OBJ = $(DEVFSADM_MOD:%=%.o) $(PLCYSRC:%.c=%.o)
+DEVFSADM_SRC = $(COMMON)/$(DEVFSADM_MOD:%=%.c) \
+		$(DEVALLOCSRC:%=$(COMMON)/%) $(PLCYSRC:%=$(COMMON)/%)
+DEVFSADM_OBJ = $(DEVFSADM_MOD:%=%.o) $(DEVALLOCSRC:%.c=%.o) $(PLCYSRC:%.c=%.o)
 
 DEVFSADM_DAEMON = devfsadmd
 
@@ -118,9 +121,9 @@
 LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2
 LINTFLAGS += -erroff=E_NAME_MULTIPLY_DEF2
 
-LAZYLIBS = -z lazyload -lzonecfg -z nolazyload
-lint := LAZYLIBS = -lzonecfg
-LDLIBS += -ldevinfo -lgen -lsysevent -lnvpair -lcmd $(LAZYLIBS)
+LAZYLIBS =	$(ZLAZYLOAD) -lzonecfg -lbsm $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -lzonecfg -lbsm
+LDLIBS += -ldevinfo -lgen -lsysevent -lnvpair -lcmd -ldoor $(LAZYLIBS) -lnsl
 
 SRCS = $(DEVFSADM_SRC) $(LINK_SRCS)
 OBJS = $(DEVFSADM_OBJ) $(LINK_OBJS)
--- a/usr/src/cmd/devfsadm/audio_link.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/audio_link.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,10 +31,13 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <stdio.h>
+#include <bsm/devalloc.h>
 
 #define	MAX_AUDIO_LINK 100
 #define	RE_SIZE 64
 
+extern int system_labeled;
+
 static void check_audio_link(char *secondary_link,
 				const char *primary_link_format);
 static int audio_process(di_minor_t minor, di_node_t node);
@@ -117,6 +119,7 @@
 static int
 audio_process(di_minor_t minor, di_node_t node)
 {
+	int flags = 0;
 	char path[PATH_MAX + 1];
 	char *buf;
 	char *mn;
@@ -209,7 +212,10 @@
 		return (DEVFSADM_CONTINUE);
 	}
 
-	(void) devfsadm_mklink(path, node, minor, 0);
+	if (system_labeled)
+		flags = DA_ADD|DA_AUDIO;
+
+	(void) devfsadm_mklink(path, node, minor, flags);
 	return (DEVFSADM_CONTINUE);
 }
 
@@ -219,17 +225,21 @@
 {
 	char primary_link[PATH_MAX + 1];
 	int i;
+	int flags = 0;
 
 	/* if link is present, return */
 	if (devfsadm_link_valid(secondary_link) == DEVFSADM_TRUE) {
 		return;
 	}
 
+	if (system_labeled)
+		flags = DA_ADD|DA_AUDIO;
+
 	for (i = 0; i < MAX_AUDIO_LINK; i++) {
 		(void) sprintf(primary_link, primary_link_format, i);
 		if (devfsadm_link_valid(primary_link) == DEVFSADM_TRUE) {
 			(void) devfsadm_secondary_link(secondary_link,
-						primary_link, 0);
+						primary_link, flags);
 			break;
 		}
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/devfsadm/devalloc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,253 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Device allocation related work.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dkio.h>
+#include <sys/wait.h>
+#include <bsm/devalloc.h>
+
+#define	DEALLOCATE	 "/usr/sbin/deallocate"
+#define	MKDEVALLOC	"/usr/sbin/mkdevalloc"
+
+static void _update_dev(deventry_t *, int, char *);
+static int _make_db();
+
+
+/*
+ * _da_check_for_usb
+ *	returns 1 if device pointed by 'link' is a removable hotplugged
+ *	else returns 0.
+ */
+int
+_da_check_for_usb(char *link, char *root_dir)
+{
+	int		fd = -1;
+	int		len, dstsize;
+	int		removable = 0;
+	char		*p = NULL;
+	char		path[MAXPATHLEN];
+
+	dstsize = sizeof (path);
+	if (strcmp(root_dir, "") != 0) {
+		if (strlcat(path, root_dir, dstsize) >= dstsize)
+			return (0);
+		len = strlen(path);
+	} else {
+		len = 0;
+	}
+	if (strstr(link, "rdsk")) {
+		(void) snprintf(path, dstsize - len, "%s", link);
+	} else if (strstr(link, "dsk")) {
+		p = rindex(link, '/');
+		if (p == NULL)
+			return (0);
+		p++;
+		(void) snprintf(path, dstsize - len, "%s%s", "/dev/rdsk/", p);
+	} else {
+		return (0);
+	}
+
+	if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
+		return (0);
+	(void) ioctl(fd, DKIOCREMOVABLE, &removable);
+	(void) close(fd);
+
+	return (removable);
+}
+
+/*
+ * _reset_devalloc
+ *	If device allocation is being turned on, creates device_allocate
+ *	device_maps if they do not exist.
+ *	Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if
+ *	device allocation is on/off.
+ */
+void
+_reset_devalloc(int action)
+{
+	da_args	dargs;
+
+	if (action == DA_ON)
+		(void) _make_db();
+	else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1))
+		return;
+
+	if (action == DA_ON)
+		dargs.optflag = DA_ON;
+	else if (action == DA_OFF)
+		dargs.optflag = DA_OFF | DA_ALLOC_ONLY;
+
+	dargs.rootdir = NULL;
+	dargs.devnames = NULL;
+	dargs.devinfo = NULL;
+
+	(void) da_update_device(&dargs);
+}
+
+/*
+ * _make_db
+ *	execs /usr/sbin/mkdevalloc to create device_allocate and
+ *	device_maps.
+ */
+static int
+_make_db()
+{
+	int	status;
+	pid_t	pid, wpid;
+
+	pid = vfork();
+	switch (pid) {
+	case -1:
+		return (1);
+	case 0:
+		if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1)
+			exit((errno == ENOENT) ? 0 : 1);
+	default:
+		for (;;) {
+			wpid = waitpid(pid, &status, 0);
+			if (wpid == (pid_t)-1) {
+				if (errno == EINTR)
+					continue;
+				else
+					return (1);
+			} else {
+				break;
+			}
+		}
+		break;
+	}
+
+	return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status));
+}
+
+
+/*
+ * _update_devalloc_db
+ * 	Forms allocatable device entries to be written to device_allocate and
+ *	device_maps.
+ */
+/* ARGSUSED */
+void
+_update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname,
+    char *root_dir)
+{
+	int		i;
+	deventry_t	*entry = NULL, *dentry = NULL;
+
+	if (action == DA_ADD) {
+		for (i = 0; i < DA_COUNT; i++) {
+			switch (i) {
+			case 0:
+				dentry = devlist->audio;
+				break;
+			case 1:
+				dentry = devlist->cd;
+				break;
+			case 2:
+				dentry = devlist->floppy;
+				break;
+			case 3:
+				dentry = devlist->tape;
+				break;
+			case 4:
+				dentry = devlist->rmdisk;
+				break;
+			default:
+				return;
+			}
+			if (dentry)
+				_update_dev(dentry, action, NULL);
+		}
+	} else if (action == DA_REMOVE) {
+		if (devflag & DA_AUDIO)
+			dentry = devlist->audio;
+		else if (devflag & DA_CD)
+			dentry = devlist->cd;
+		else if (devflag & DA_FLOPPY)
+			dentry = devlist->floppy;
+		else if (devflag & DA_TAPE)
+			dentry = devlist->tape;
+		else if (devflag & DA_RMDISK)
+			dentry = devlist->rmdisk;
+		else
+			return;
+
+		for (entry = dentry; entry != NULL; entry = entry->next) {
+			if (strcmp(entry->devinfo.devname, devname) == 0)
+				break;
+		}
+		_update_dev(entry, action, devname);
+	}
+}
+
+static void
+_update_dev(deventry_t *dentry, int action, char *devname)
+{
+	da_args		dargs;
+	deventry_t	newentry, *entry;
+
+	dargs.rootdir = NULL;
+	dargs.devnames = NULL;
+
+	if (action == DA_ADD) {
+		dargs.optflag = DA_ADD | DA_FORCE;
+		for (entry = dentry; entry != NULL; entry = entry->next) {
+			dargs.devinfo = &(entry->devinfo);
+			(void) da_update_device(&dargs);
+		}
+	} else if (action == DA_REMOVE) {
+		dargs.optflag = DA_REMOVE;
+		if (dentry) {
+			entry = dentry;
+		} else {
+			newentry.devinfo.devname = strdup(devname);
+			newentry.devinfo.devtype =
+			newentry.devinfo.devauths =
+			newentry.devinfo.devexec =
+			newentry.devinfo.devopts =
+			newentry.devinfo.devlist = NULL;
+			newentry.devinfo.instance = 0;
+			newentry.next = NULL;
+			entry = &newentry;
+		}
+		dargs.devinfo = &(entry->devinfo);
+		(void) da_update_device(&dargs);
+	}
+}
--- a/usr/src/cmd/devfsadm/devfsadm.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/devfsadm.c	Fri Mar 24 12:29:20 2006 -0800
@@ -36,10 +36,18 @@
  * reconfiguration for hotplugging support.
  */
 
-#include "devfsadm_impl.h"
+#include <string.h>
+#include <tsol/label.h>
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
 #include <utime.h>
-
-/* globals */
+#include "devfsadm_impl.h"
+
+/* externs from devalloc.c */
+
+extern void  _reset_devalloc(int);
+extern void _update_devalloc_db(devlist_t *, int, int, char *, char *);
+extern int _da_check_for_usb(char *, char *);
 
 /* create or remove nodes or links. unset with -n */
 static int file_mods = TRUE;
@@ -50,12 +58,26 @@
 /* devlinks -d compatibility */
 static int devlinks_debug = FALSE;
 
-/* turn off device allocation with devfsadm -d */
-static int devalloc_off = FALSE;
-
-/* devices to be deallocated with -d */
-static char *devalloc[5] =
-	{DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_FD, DDI_NT_TAPE, NULL};
+/* flag to check if system is labeled */
+int system_labeled = FALSE;
+
+/* flag to enable/disable device allocation with -e/-d */
+static int devalloc_flag = 0;
+
+/* flag to update device allocation database for this device type */
+static int update_devdb = 0;
+
+/*
+ * devices to be deallocated with -d :
+ *	audio, floppy, cd, floppy, tape, rmdisk.
+ */
+static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN,
+				    DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN,
+				    DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT,
+				    DDI_NT_SCSI_NEXUS, NULL};
+
+/* list of allocatable devices */
+static devlist_t devlist;
 
 /* load a single driver only.  set with -i */
 static int single_drv = FALSE;
@@ -210,6 +232,7 @@
 int
 main(int argc, char *argv[])
 {
+	struct stat tx_stat;
 	struct passwd *pw;
 	struct group *gp;
 	pid_t pid;
@@ -251,10 +274,26 @@
 
 	(void) umask(0);
 
+	system_labeled = is_system_labeled();
+	if (system_labeled == FALSE) {
+		/*
+		 * is_system_labeled() will return false in case we are
+		 * starting before the first reboot after Trusted Extensions
+		 * is installed. we check for a well known TX binary to
+		 * to see if TX is installed.
+		 */
+		if (stat(DA_LABEL_CHECK, &tx_stat) == 0)
+			system_labeled = TRUE;
+	}
+
 	parse_args(argc, argv);
 
 	(void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL);
 
+	/* Initialize device allocation list */
+	devlist.audio = devlist.cd = devlist.floppy = devlist.tape =
+	devlist.rmdisk = NULL;
+
 	if (daemon_mode == TRUE) {
 		/*
 		 * Build /dev and /devices before daemonizing if
@@ -311,7 +350,6 @@
 				(void) rcm_init();
 				login_dev_enable = TRUE;
 			}
-
 			daemon_update();
 		} else {
 			err_print(DAEMON_RUNNING, pid);
@@ -322,6 +360,9 @@
 	} else {
 		/* not a daemon, so just build /dev and /devices */
 		process_devinfo_tree();
+		if (devalloc_flag != 0)
+			/* Enable/disable device allocation */
+			_reset_devalloc(devalloc_flag);
 	}
 	return (0);
 }
@@ -607,7 +648,7 @@
 		devlinktab_file = DEVLINKTAB_FILE;
 
 		while ((opt = getopt(argc, argv,
-		    "Cc:dIi:l:np:PR:r:st:vV:x:z:Z:")) != EOF) {
+		    "Cc:deIi:l:np:PR:r:st:vV:x:z:Z:")) != EOF) {
 			if (opt == 'I' || opt == 'P') {
 				if (public_mode)
 					usage();
@@ -626,9 +667,21 @@
 						    sizeof (char *));
 				classes[num_classes - 1] = optarg;
 				break;
-			case  'd':
+			case 'd':
 				if (daemon_mode == FALSE) {
-					devalloc_off = TRUE;
+					/*
+					 * Device allocation to be disabled.
+					 */
+					devalloc_flag = DA_OFF;
+					build_dev = FALSE;
+				}
+				break;
+			case 'e':
+				if (daemon_mode == FALSE) {
+					/*
+					 * Device allocation to be enabled.
+					 */
+					devalloc_flag = DA_ON;
 					build_dev = FALSE;
 				}
 				break;
@@ -909,6 +962,12 @@
 	if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl)
 		(void) notify_rcm(node, dcip->dci_minor);
 
+	/* Add new device to device allocation database */
+	if (system_labeled && update_devdb) {
+		_update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir);
+		update_devdb = 0;
+	}
+
 	di_fini(node);
 }
 
@@ -986,7 +1045,7 @@
 
 	} else if (load_attach_drv == TRUE) {
 		/*
-		 * load and attach all drivers, then walk the entire tree.
+		 * Load and attach all drivers, then walk the entire tree.
 		 * If the cache flag is set, use DINFOCACHE to get cached
 		 * data.
 		 */
@@ -2825,11 +2884,33 @@
 	    == DEVFSADM_SUCCESS) {
 		linknew = TRUE;
 		add_link_to_cache(link, acontents);
+		if (system_labeled && (flags & DA_ADD)) {
+			/*
+			 * Add this device to the list of allocatable devices.
+			 */
+			int	instance = di_instance(node);
+
+			(void) da_add_list(&devlist, devlink, instance, flags);
+			update_devdb = flags;
+		}
 	} else {
 		linknew = FALSE;
 	}
 
 	if (link_exists == TRUE) {
+		if (system_labeled && (flags & DA_CD)) {
+			/*
+			 * if this is a removable disk, add it
+			 * as that to device allocation database.
+			 */
+			if (_da_check_for_usb(devlink, root_dir) == 1) {
+				int instance = di_instance(node);
+
+				(void) da_add_list(&devlist, devlink, instance,
+				    DA_ADD|DA_RMDISK);
+				update_devdb = DA_RMDISK;
+			}
+		}
 		/* Link exists or was just created */
 		(void) di_devlink_add_link(devlink_cache, link, rcontents,
 		    DI_PRIMARY_LINK);
@@ -2935,6 +3016,19 @@
 		 */
 		add_link_to_cache(link, lphy_path);
 		linknew = TRUE;
+		if (system_labeled &&
+		    ((flags & DA_AUDIO) && (flags & DA_ADD))) {
+			/*
+			 * Add this device to the list of allocatable devices.
+			 */
+			int	instance = 0;
+
+			op = strrchr(contents, '/');
+			op++;
+			(void) sscanf(op, "%d", &instance);
+			(void) da_add_list(&devlist, devlink, instance, flags);
+			update_devdb = flags;
+		}
 	} else {
 		linknew = FALSE;
 	}
@@ -3228,6 +3322,7 @@
 static void
 reset_node_permissions(di_node_t node, di_minor_t minor)
 {
+	int devalloc_is_on = 0;
 	int spectype;
 	char phy_path[PATH_MAX + 1];
 	mode_t mode;
@@ -3281,32 +3376,52 @@
 	}
 
 	/*
-	 * If we are here for deactivating device allocation, set
-	 * default permissions. Otherwise, set default permissions
-	 * only if this is a new device because we want to preserve
-	 * modified user permissions.
-	 * Devfs indicates a new device by faking an access time
-	 * of zero.
+	 * If we are here for a new device
+	 *	If device allocation is on
+	 *	then
+	 *		set ownership to root:other and permissions to 0000
+	 *	else
+	 *		set ownership and permissions as specified in minor_perm
+	 * If we are here for an existing device
+	 *	If device allocation is to be turned on
+	 *	then
+	 *		reset ownership to root:other and permissions to 0000
+	 *	else if device allocation is to be turned off
+	 *		reset ownership and permissions to those specified in
+	 *		minor_perm
+	 *	else
+	 *		preserve exsisting/user-modified ownership and
+	 *		permissions
+	 *
+	 * devfs indicates a new device by faking access time to be zero.
 	 */
+	devalloc_is_on = da_is_on();
 	if (sb.st_atime != 0) {
 		int  i;
 		char *nt;
 
-		if (devalloc_off == FALSE)
+		if ((devalloc_flag == 0) && (devalloc_is_on != 1))
+			/*
+			 * Leave existing devices as they are if we are not
+			 * turning device allocation on/off.
+			 */
 			return;
 
 		nt = di_minor_nodetype(minor);
+
 		if (nt == NULL)
 			return;
-		for (i = 0; devalloc[i]; i++) {
-			if (strcmp(nt, devalloc[i]) == 0)
+
+		for (i = 0; devalloc_list[i]; i++) {
+			if (strcmp(nt, devalloc_list[i]) == 0)
+				/*
+				 * One of the types recognized by devalloc,
+				 * reset attrs.
+				 */
 				break;
 		}
-
-		if (devalloc[i] == NULL)
+		if (devalloc_list[i] == NULL)
 			return;
-
-		/* One of the types recognized by devalloc, reset perms */
 	}
 
 	if (file_mods == FALSE) {
@@ -3315,12 +3430,24 @@
 		return;
 	}
 
-	if (sb.st_mode != mode) {
+	if ((devalloc_flag == DA_ON) || (devalloc_is_on == 1)) {
+		/*
+		 * we are here either to turn device allocation on
+		 * or to add a new device while device allocation in on
+		 */
+		mode = DEALLOC_MODE;
+		uid = DA_UID;
+		gid = DA_GID;
+	}
+
+	if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
+	    (sb.st_mode != mode)) {
 		if (chmod(phy_path, mode) == -1)
 			vprint(VERBOSE_MID, CHMOD_FAILED,
 			    phy_path, strerror(errno));
 	}
-	if (sb.st_uid != uid || sb.st_gid != gid) {
+	if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
+	    (sb.st_uid != uid || sb.st_gid != gid)) {
 		if (chown(phy_path, uid, gid) == -1)
 			vprint(VERBOSE_MID, CHOWN_FAILED,
 			    phy_path, strerror(errno));
@@ -4483,6 +4610,27 @@
 		}
 	}
 
+	/* update device allocation database */
+	if (system_labeled) {
+		int	ret = 0;
+		int	devtype = 0;
+		char	devname[MAXNAMELEN];
+
+		devname[0] = '\0';
+		if (strstr(node_path, DA_SOUND_NAME))
+			devtype = DA_AUDIO;
+		else if (strstr(node_path, "disk"))
+			devtype = DA_RMDISK;
+		else
+			goto out;
+		ret = da_remove_list(&devlist, NULL, devtype, devname,
+		    sizeof (devname));
+		if (ret != -1)
+			(void) _update_devalloc_db(&devlist, devtype, DA_REMOVE,
+			    devname, root_dir);
+	}
+
+out:
 	/* now log an event */
 	if (nvl) {
 		log_event(EC_DEV_REMOVE, ev_subclass, nvl);
@@ -4610,8 +4758,9 @@
 devfsadm_link_valid(char *link)
 {
 	struct stat sb;
-	char devlink[PATH_MAX + 1], *contents;
+	char devlink[PATH_MAX + 1], *contents = NULL;
 	int rv, type;
+	int instance = 0;
 
 	/* prepend link with dev_dir contents */
 	(void) strcpy(devlink, dev_dir);
@@ -4634,6 +4783,13 @@
 	 * The link exists. Add it to the database
 	 */
 	(void) di_devlink_add_link(devlink_cache, link, contents, type);
+	if (system_labeled && (rv == DEVFSADM_TRUE) &&
+	    strstr(devlink, DA_AUDIO_NAME) && contents) {
+		(void) sscanf(contents, "%*[a-z]%d", &instance);
+		(void) da_add_list(&devlist, devlink, instance,
+		    DA_ADD|DA_AUDIO);
+		_update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir);
+	}
 	free(contents);
 
 	return (rv);
--- a/usr/src/cmd/devfsadm/disk_link.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/disk_link.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +31,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <bsm/devalloc.h>
 
 #define	DISK_SUBPATH_MAX 100
 #define	RM_STALE 0x01
@@ -46,6 +46,8 @@
 #define	MN_EFI		"wd"
 #define	ASCIIWWNSIZE	255
 
+extern int system_labeled;
+
 static int disk_callback_chan(di_minor_t minor, di_node_t node);
 static int disk_callback_nchan(di_minor_t minor, di_node_t node);
 static int disk_callback_wwn(di_minor_t minor, di_node_t node);
@@ -209,6 +211,8 @@
 	char slice[4];
 	char *mn;
 	char *ctrl;
+	char *nt = NULL;
+	int  nflags = 0;
 
 	if (strstr(mn = di_minor_name(minor), ",raw")) {
 		dir = "rdsk";
@@ -255,7 +259,17 @@
 	}
 	(void) strcat(l_path, slice);
 
-	(void) devfsadm_mklink(l_path, node, minor, 0);
+	if (system_labeled) {
+		nt = di_minor_nodetype(minor);
+		if ((nt != NULL) &&
+		    ((strcmp(nt, DDI_NT_CD) == 0) ||
+		    (strcmp(nt, DDI_NT_CD_CHAN) == 0) ||
+		    (strcmp(nt, DDI_NT_BLOCK_CHAN) == 0))) {
+			nflags = DA_ADD|DA_CD;
+		}
+	}
+
+	(void) devfsadm_mklink(l_path, node, minor, nflags);
 
 	if ((flags & RM_STALE) == RM_STALE) {
 		(void) strcpy(stale_re, "^");
--- a/usr/src/cmd/devfsadm/i386/misc_link_i386.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/i386/misc_link_i386.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -34,6 +33,9 @@
 #include <limits.h>
 #include <ctype.h>
 #include <sys/mc.h>
+#include <bsm/devalloc.h>
+
+extern int system_labeled;
 
 static int lp(di_minor_t minor, di_node_t node);
 static int serial_dialout(di_minor_t minor, di_node_t node);
@@ -151,16 +153,20 @@
 static int
 diskette(di_minor_t minor, di_node_t node)
 {
+	int flags = 0;
 	char *a2;
 	char link[PATH_MAX];
 	char *addr = di_bus_addr(node);
 	char *mn = di_minor_name(minor);
 
+	if (system_labeled)
+		flags = DA_ADD|DA_FLOPPY;
+
 	if (strcmp(addr, "0,0") == 0) {
 		if (strcmp(mn, "c") == 0) {
-			(void) devfsadm_mklink("diskette", node, minor, 0);
+			(void) devfsadm_mklink("diskette", node, minor, flags);
 		} else if (strcmp(mn, "c,raw") == 0) {
-			(void) devfsadm_mklink("rdiskette", node, minor, 0);
+			(void) devfsadm_mklink("rdiskette", node, minor, flags);
 		}
 
 	}
@@ -171,11 +177,13 @@
 			if (strcmp(mn, "c") == 0) {
 				(void) strcpy(link, "diskette");
 				(void) strcat(link, a2);
-				(void) devfsadm_mklink(link, node, minor, 0);
+				(void) devfsadm_mklink(link, node, minor,
+				    flags);
 			} else if (strcmp(mn, "c,raw") == 0) {
 				(void) strcpy(link, "rdiskette");
 				(void) strcat(link, a2);
-				(void) devfsadm_mklink(link, node, minor, 0);
+				(void) devfsadm_mklink(link, node, minor,
+				    flags);
 			}
 		}
 	}
--- a/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,6 +32,9 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <sys/mkdev.h>
+#include <bsm/devalloc.h>
+
+extern int system_labeled;
 
 static int node_name(di_minor_t minor, di_node_t node);
 
@@ -123,14 +125,19 @@
 static int
 diskette(di_minor_t minor, di_node_t node)
 {
-	char *mn = di_minor_name(minor);
+	int	flags = 0;
+	char	*mn = di_minor_name(minor);
+
+	if (system_labeled)
+		flags = DA_ADD|DA_FLOPPY;
+
 	if (strcmp(mn, "c") == 0) {
-		(void) devfsadm_mklink("diskette", node, minor, 0);
-		(void) devfsadm_mklink("diskette0", node, minor, 0);
+		(void) devfsadm_mklink("diskette", node, minor, flags);
+		(void) devfsadm_mklink("diskette0", node, minor, flags);
 
 	} else if (strcmp(mn, "c,raw") == 0) {
-		(void) devfsadm_mklink("rdiskette", node, minor, 0);
-		(void) devfsadm_mklink("rdiskette0", node, minor, 0);
+		(void) devfsadm_mklink("rdiskette", node, minor, flags);
+		(void) devfsadm_mklink("rdiskette0", node, minor, flags);
 
 	}
 	return (DEVFSADM_CONTINUE);
--- a/usr/src/cmd/devfsadm/tape_link.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/tape_link.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,7 +29,9 @@
 #include <strings.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <bsm/devalloc.h>
 
+extern int system_labeled;
 
 static int tape_process(di_minor_t minor, di_node_t node);
 
@@ -60,6 +61,7 @@
 static int
 tape_process(di_minor_t minor, di_node_t node)
 {
+	int flags = 0;
 	char l_path[PATH_MAX + 1];
 	char *buf;
 	char *mn;
@@ -98,7 +100,10 @@
 	(void) strcat(l_path, mn);
 	free(buf);
 
-	(void) devfsadm_mklink(l_path, node, minor, 0);
+	if (system_labeled)
+		flags = DA_ADD|DA_TAPE;
+
+	(void) devfsadm_mklink(l_path, node, minor, flags);
 
 	return (DEVFSADM_CONTINUE);
 }
--- a/usr/src/cmd/devfsadm/usb_link.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/devfsadm/usb_link.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -210,6 +209,7 @@
 	char *l_path, *p_path, *buf, *devfspath;
 	char *minor_nm, *drvr_nm, *name = (char *)NULL;
 	int i, index;
+	int flags = 0;
 	int create_secondary_link = 0;
 
 	minor_nm = di_minor_name(minor);
@@ -345,7 +345,7 @@
 
 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
 
-	(void) devfsadm_mklink(l_path, node, minor, 0);
+	(void) devfsadm_mklink(l_path, node, minor, flags);
 
 	if (create_secondary_link) {
 		/*
@@ -376,6 +376,7 @@
 	char ugen_RE[128];
 	devfsadm_enumerate_t ugen_rules[1];
 	char l_path[PATH_MAX];
+	int flags = 0;
 
 	devfsadm_print(debug_mid, "ugen_create_link: p_path=%s name=%s\n",
 	    p_path, node_name);
@@ -418,7 +419,7 @@
 
 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
 
-	(void) devfsadm_mklink(l_path, node, minor, 0);
+	(void) devfsadm_mklink(l_path, node, minor, flags);
 
 	free(buf);
 }
--- a/usr/src/cmd/dminfo/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 1989, 2002 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-
-PROG= dminfo
-
-OBJS=	dminfo.o
-SRCS=	$(OBJS:%.o=%.c)
-
-include ../Makefile.cmd
-
-TEXT_DOMAIN=SUNW_BSM_DMINFO
-POS=dminfo.po
-include ../Makefile.cmd.bsm
-
-FILEMODE=	755
-
-LDLIBS += -lbsm
-
-.KEEP_STATE:
-
-all: $(PROG)
-
-install: all $(ROOTUSRSBINPROG)
-
-clean:
-	rm -rf $(OBJS) $(POS)
-
-lint:	lint_PROG
-
-include ../Makefile.targ
--- a/usr/src/cmd/dminfo/dminfo.c	Thu Mar 23 19:49:27 2006 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,479 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#if !defined(lint) && defined(SCCSIDS)
-static char	*bsm_sccsid =
-		    "@(#)dminfo.c	1.8	05/06/15 SMI; SunOS BSM";
-#endif
-
-#include <locale.h>
-#include <stdio.h>
-#include <string.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <memory.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <fcntl.h>
-#include <bsm/devices.h>
-#define	DMPFILE	"/etc/security/device_maps"
-#define	RETRY_SLEEP	6
-#define	RETRY_COUNT	10
-#define	EINVOKE	2
-#define	EFAIL 1
-
-#if !defined(TEXT_DOMAIN)
-#define	TEXT_DOMAIN "SUNW_BSM_DMINFO"
-#endif
-
-extern off_t lseek();
-
-char	*getdmapfield();
-char	*getdmapdfield();
-static void	printdmapent();
-static void	dmapi_err();
-
-static char	*prog_name;
-
-/*
- * printdmapent(dmapp) prints a devmap_t structure pointed to by dmapp.
- */
-static void
-printdmapent(dmapp)
-	devmap_t *dmapp;
-{
-	(void) printf("%s:", dmapp->dmap_devname);
-	(void) printf("%s:", dmapp->dmap_devtype);
-	(void) printf("%s:", dmapp->dmap_devlist);
-	(void) printf("\n");
-}
-
-
-/*
- * dmapi_err(exit_code,err_msg) prints message pointed to by err_msg to
- * stderr. Then prints usage message to stderr. Then exits program with
- * exit_code.
- *
- */
-static void
-dmapi_err(exit_code, err_msg)
-int	exit_code;
-char	*err_msg;
-{
-	if (err_msg != NULL) {
-		(void) fprintf(stderr, "dmapinfo:%s\n", err_msg);
-	}
-	if (exit_code == EINVOKE) {
-		(void) fprintf(stderr,
-			"Usage: %s [-v] [-a] [-f filename] %s\n",
-			prog_name,
-			"[-d device ...]");
-		(void) fprintf(stderr,
-			"       %s [-v] [-a] [-f filename] %s\n",
-			prog_name,
-			"[-n name ...]");
-		(void) fprintf(stderr,
-			"       %s [-v] [-a] [-f filename] %s\n",
-			prog_name,
-			"[-t type ...]");
-		(void) fprintf(stderr,
-			"       %s [-v] [-a] [-f filename] %s\n",
-			prog_name,
-			"[-u Entry]");
-	}
-	exit(exit_code);
-}
-
-
-int
-main(int argc, char *argv[])
-{
-	devmap_t *dmapp;
-	devmap_t dmap;
-	char	*mptr;
-	char	*tptr;
-	char	*nptr;
-	char	*filename = DMPFILE;
-	int	name = 0;
-	int	device = 0;
-	int	file = 0;
-	int	verbose = 0;
-	int	cntr = 0;
-	int	any = 0;
-	int	update = 0;
-	int	tp = 0;
-	int	des;
-	int	status;
-
-	/* Internationalization */
-	(void) setlocale(LC_ALL, "");
-	(void) textdomain(TEXT_DOMAIN);
-
-	/*
-	 * point prog_name to invocation name
-	 */
-	if ((tptr = strrchr(*argv, '/')) != NULL)
-		prog_name = ++tptr;
-		else
-		prog_name = *argv;
-	argc--;
-	argv++;
-	/*
-	 * parse arguments
-	 */
-	while ((argc >= 1) && (argv[0][0] == '-')) {
-		switch (argv[0][1]) {
-		case 'a':
-			any++;
-			break;
-		case 'd':
-			if ((name) || (device) || (update) || (tp)) {
-				dmapi_err(EINVOKE,
-					gettext("option conflict"));
-			}
-			device++;
-			break;
-		case 'f':
-			argc--;
-			argv++;
-			if (argc <= 0)
-				dmapi_err(EINVOKE,
-					gettext("missing file name"));
-			filename = *argv;
-			file++;
-			break;
-		case 'n':
-			if ((name) || (device) || (update) || (tp)) {
-				dmapi_err(EINVOKE,
-					gettext("option conflict"));
-			}
-			name++;
-			break;
-		case 't':
-			if ((name) || (device) || (update) || (tp)) {
-				dmapi_err(EINVOKE,
-					gettext("option conflict"));
-			}
-			tp++;
-			break;
-		case 'u':
-			if ((name) || (device) || (update) || (tp)) {
-				dmapi_err(EINVOKE,
-					gettext("option conflict"));
-			}
-			update++;
-			break;
-		case 'v':
-			verbose++;
-			break;
-		default:
-			dmapi_err(EINVOKE,
-				gettext("bad option"));
-			break;
-		}
-		argc--;
-		argv++;
-	}
-	/*
-	 * -d(device) -n(name) and -u(update) switches require at least one
-	 * argument.
-	 */
-	if (file)
-		setdmapfile(filename);
-	if ((device) || (name) || (update) || (tp)) {
-		if (argc < 1) {
-			dmapi_err(EINVOKE,
-				gettext("insufficient args for this option"));
-		}
-	}
-	if (update) {
-		/*
-		 * -u(update) switch requires only one argument
-		 */
-		if (argc != 1) {
-			dmapi_err(EINVOKE,
-				gettext("too many args for this option"));
-		}
-		/*
-		 * read entry argument from stdin into a devmap_t known as dmap
-		 */
-		if ((dmap.dmap_devname = getdmapfield(*argv)) == NULL) {
-			dmapi_err(EINVOKE,
-				gettext("Bad dmap_devname in entry argument"));
-		}
-		if ((dmap.dmap_devtype = getdmapfield((char *)NULL)) ==
-			NULL) {
-			dmapi_err(EINVOKE,
-				gettext("Bad dmap_devtype in entry Argument"));
-		}
-		if ((dmap.dmap_devlist = getdmapfield((char *)NULL)) ==
-			NULL) {
-			dmapi_err(EINVOKE,
-				gettext("Bad dmap_devlist in entry argument"));
-		}
-		/*
-		 * Find out how long device list is and create a buffer to
-		 * hold it.  Then copy it there. This is done since we do not
-		 * want to corrupt the existing string.
-		 */
-		cntr = strlen(dmap.dmap_devlist) + 1;
-		mptr = calloc((unsigned)cntr, sizeof (char));
-		if (mptr == NULL) {
-			if (verbose) {
-				(void) fprintf(stderr,
-					gettext(
-					"dmapinfo: Cannot calloc memory\n"));
-			}
-			exit(1);
-		}
-		(void) strcpy(mptr, dmap.dmap_devlist);
-		/*
-		 * open the device maps file for read/ write. We are not
-		 * sure we want to write to it yet but we may and this is a
-		 * easy way to get the file descriptor. We want the file
-		 * descriptor so we can lock the file.
-		 */
-		if ((des = open(filename, O_RDWR)) < 0) {
-			if (verbose) {
-				(void) fprintf(stderr,
-				gettext("dmapinfo: Cannot open %s\n"),
-				    filename);
-			}
-			exit(1);
-		}
-		cntr = 0;
-#ifdef CMW
-		while ((status = flock(des, LOCK_EX | LOCK_NB) == -1) &&
-			(cntr++ < RETRY_COUNT)) {
-			(void) sleep(RETRY_SLEEP);
-		}
-#else
-		while (((status = lockf(des, F_TLOCK, 0)) == -1) &&
-			(cntr++ < RETRY_COUNT)) {
-			(void) sleep(RETRY_SLEEP);
-		}
-#endif
-		if (status == -1) {
-			if (verbose) {
-				(void) fprintf(stderr,
-			gettext("dmapinfo: Cannot lock %s\n"), filename);
-			}
-			exit(1);
-		}
-		/*
-		 * Now that we have the device_maps file then lets check
-		 * for previous entrys with the same name.  If it already
-		 * exists then we will exit with status of 1.
-		 */
-		if (verbose) {
-			(void) fprintf(stderr,
-			gettext("dmapinfo: Checking %s for name (%s).\n"),
-				filename, dmap.dmap_devname);
-		}
-		if (getdmapnam(dmap.dmap_devname) != NULL) {
-			if (verbose) {
-				(void) fprintf(stderr,
-			gettext("dmapinfo: Device name (%s) found in %s.\n"),
-					dmap.dmap_devname, filename);
-			}
-			exit(1);
-		}
-		if (verbose) {
-			(void) fprintf(stderr,
-		gettext("dmapinfo: Device name (%s) not found in %s.\n"),
-				dmap.dmap_devname, filename);
-		}
-		/*
-		 * We now Know name does not exist and now we need to check
-		 * to see if any of the devices in the device list are in the
-		 * device maps file. If the already exist then we will exit
-		 * with a status of 1.
-		 */
-		nptr = mptr;
-		nptr = getdmapdfield(nptr);
-		while (nptr) {
-			if (verbose) {
-(void) fprintf(stderr, gettext("dmapinfo: Check %s for device (%s).\n"),
-				filename, nptr);
-			}
-			if (getdmapdev(nptr) != NULL) {
-				if (verbose) {
-(void) fprintf(stderr, gettext("dmapinfo: Device (%s) found in %s.\n"),
-					nptr, filename);
-				}
-				exit(1);
-			}
-			if (verbose) {
-(void) fprintf(stderr, gettext("dmapinfo: Device (%s) not found in %s.\n"),
-					nptr, filename);
-			}
-			nptr = getdmapdfield((char *)NULL);
-		}
-		/*
-		 * Good the entry is uniq. So lets find out how long it is
-		 * and add it to the end of device maps file in a pretty
-		 * way.
-		 */
-		if (verbose) {
-			(void) fprintf(stderr, "dmapinfo: Adding entry to %s\n",
-				filename);
-			printdmapent(&dmap);
-		}
-		cntr = strlen(dmap.dmap_devname);
-		cntr += strlen(dmap.dmap_devtype);
-		cntr += strlen(dmap.dmap_devlist);
-		cntr += 15;
-		tptr = calloc((unsigned)cntr, sizeof (char));
-		if (tptr == NULL) {
-			exit(1);
-		}
-		(void) strcat(tptr, dmap.dmap_devname);
-		(void) strcat(tptr, ":\\\n\t");
-		(void) strcat(tptr, dmap.dmap_devtype);
-		(void) strcat(tptr, ":\\\n\t");
-		(void) strcat(tptr, dmap.dmap_devlist);
-		(void) strcat(tptr, ":\\\n\t");
-		(void) strcat(tptr, "\n");
-		cntr = strlen(tptr);
-#ifdef CMW
-		if (lseek(des, 0L, L_XTND) == -1L) {
-			exit(1);
-		}
-#else
-		if (lseek(des, 0L, SEEK_END) == -1L) {
-			exit(1);
-		}
-#endif
-		if (write(des, tptr, cntr) == -1) {
-			exit(1);
-		}
-		if (close(des) == -1) {
-			exit(1);
-		}
-		if (verbose) {
-			(void) fprintf(stderr, "dmapinfo: Entry added to %s\n",
-				filename);
-		}
-		exit(0);
-	}
-	/*
-	 * Look for devices in device_maps file. If verbose switch is set
-	 * then print entry(s) found. If "any" switch  is set then, if any
-	 * device is found will result in a exit status of 0. If "any" switch
-	 * is not set then, if any device is not will result in a exit status
-	 * of 1.
-	 */
-	if (device) {
-		while (argc >= 1) {
-			if ((dmapp = getdmapdev(*argv)) != NULL) {
-				if (verbose) {
-					printdmapent(dmapp);
-				}
-				cntr++;
-			} else if (any == 0)
-				exit(1);
-			argc--;
-			argv++;
-		}
-		if (cntr != 0)
-			exit(0);
-		exit(1);
-	}
-	/*
-	 * Look for names in device_maps file. If verbose switch is set
-	 * then print entry(s) found. If "any" switch  is set then, if any
-	 * name is found will result in a exit status of 0. If "any" switch
-	 * is not set then, if any name is not will result in a exit status
-	 * of 1.
-	 */
-	if (name) {
-		while (argc >= 1) {
-			if ((dmapp = getdmapnam(*argv)) != NULL) {
-				if (verbose) {
-					printdmapent(dmapp);
-				}
-				cntr++;
-			} else if (any == 0)
-				exit(1);
-			argc--;
-			argv++;
-		}
-		if (cntr != 0)
-			exit(0);
-		exit(1);
-	}
-	/*
-	 * Read all entrys from device maps file. If verbose flag is set
-	 * then all the device maps files are printed.  This is useful for
-	 * piping to grep. Also this option used without the verbose option
-	 * is useful to check for device maps file and for at least one
-	 * entry.  If the device maps file is found and there is one entry
-	 * the return status is 0.
-	 */
-	if (tp) {
-		cntr = 0;
-		while (argc >= 1) {
-			setdmapent();
-			while ((dmapp = getdmaptype(*argv)) != 0) {
-				cntr++;
-				if (verbose) {
-					printdmapent(dmapp);
-				}
-			}
-			enddmapent();
-			if ((any == 0) && (cntr == 0))
-				exit(1);
-			argc--;
-			argv++;
-		}
-		if (cntr == 0)
-			exit(1);
-		exit(0);
-	}
-	/*
-	 * Read all entrys from device maps file. If verbose flag is set
-	 * then all the device maps files are printed.  This is useful for
-	 * piping to grep. Also this option used without the verbose option
-	 * is useful to check for device maps file and for atleast one
-	 * entry.  If the device maps file is found and there is one entry
-	 * the return status is 0.
-	 */
-	cntr = 0;
-	setdmapent();
-	while ((dmapp = getdmapent()) != 0) {
-		cntr++;
-		if (verbose) {
-			printdmapent(dmapp);
-		}
-	}
-	enddmapent();
-	if (cntr == 0)
-		exit(1);
-	return (0);
-}
--- a/usr/src/cmd/fs.d/autofs/auto_subr.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/autofs/auto_subr.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1988-1999 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -54,6 +53,9 @@
 #include <rpcsvc/nfs_prot.h>
 #include <assert.h>
 #include "automount.h"
+#include <zone.h>
+#include <priv.h>
+#include <fcntl.h>
 
 static char *check_hier(char *);
 static int natisa(char *, size_t);
@@ -62,9 +64,111 @@
 
 static bool_t nodirect_map = FALSE;
 
+/*
+ * If the system is labeled then we need to
+ * have a uniquely-named auto_home map for each zone.
+ * The maps are made unique by appending the zonename.
+ * The home directory is made unique by prepending /zone/<zonename>
+ * for each zone that is dominated by the current zone.
+ * The current zone's home directory mount point is not changed.
+ *
+ * For each auto_home_<zonename> a default template map is created
+ * only if it doesn't exist yet. The default entry is used to declare
+ * local home directories created within each zone. For example:
+ *
+ *	+auto_home_public
+ *      * -fstype=lofs :/zone/public/export/home/&
+ */
+static void
+loadzone_maps(char *mntpnt, char *map, char *opts, char **stack, char ***stkptr)
+{
+	zoneid_t *zids = NULL;
+	zoneid_t my_zoneid;
+	uint_t nzents_saved;
+	uint_t nzents;
+	int i;
+
+	if (!priv_ineffect(PRIV_SYS_MOUNT))
+		return;
+
+	if (zone_list(NULL, &nzents) != 0) {
+		return;
+	}
+	my_zoneid = getzoneid();
+again:
+	if (nzents == 0)
+		return;
+
+	zids = malloc(nzents * sizeof (zoneid_t));
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		free(zids);
+		return;
+	}
+	if (nzents != nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	for (i = 0; i < nzents; i++) {
+		char zonename[ZONENAME_MAX];
+		char zoneroot[MAXPATHLEN];
+
+		if (getzonenamebyid(zids[i], zonename, ZONENAME_MAX) != -1) {
+			char appended_map[MAXPATHLEN];
+			char prepended_mntpnt[MAXPATHLEN];
+			char map_path[MAXPATHLEN];
+			int fd;
+
+			(void) snprintf(appended_map, sizeof (appended_map),
+			    "%s_%s", map, zonename);
+
+			/* for current zone, leave mntpnt alone */
+			if (zids[i] != my_zoneid) {
+				(void) snprintf(prepended_mntpnt,
+				    sizeof (prepended_mntpnt),
+				    "/zone/%s%s", zonename, mntpnt);
+				if (zone_getattr(zids[i], ZONE_ATTR_ROOT,
+				    zoneroot, sizeof (zoneroot)) == -1)
+					continue;
+			} else {
+				(void) strcpy(prepended_mntpnt, mntpnt);
+				zoneroot[0] = '\0';
+			}
+
+			dirinit(prepended_mntpnt, appended_map, opts, 0, stack,
+			    stkptr);
+			/*
+			 * Next create auto_home_<zone> maps for each zone
+			 */
+
+			(void) snprintf(map_path, sizeof (map_path),
+			    "/etc/%s", appended_map);
+			/*
+			 * If the map file doesn't exist create a template
+			 */
+			if ((fd = open(map_path, O_RDWR | O_CREAT | O_EXCL,
+			    S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) {
+				int len;
+				char map_rec[MAXPATHLEN];
+
+				len = snprintf(map_rec, sizeof (map_rec),
+				    "+%s\n*\t-fstype=lofs\t:%s/export/home/&\n",
+				    appended_map, zoneroot);
+				if (len <= sizeof (map_rec))
+					(void) write(fd, map_rec, len);
+				(void) close(fd);
+			}
+		}
+	}
+	free(zids);
+}
+
 void
 dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack,
-	char ***stkptr)
+    char ***stkptr)
 {
 	struct autodir *dir;
 	char *p;
@@ -97,6 +201,16 @@
 		return;
 	}
 
+	/*
+	 * Home directories are polyinstantiated on
+	 * labeled systems.
+	 */
+	if (is_system_labeled() &&
+	    (strcmp(mntpnt, "/home") == 0) &&
+	    (strcmp(map, "auto_home") == 0)) {
+		(void) loadzone_maps(mntpnt, map, opts, stack, stkptr);
+		return;
+	}
 enter:
 	dir = (struct autodir *)malloc(sizeof (*dir));
 	if (dir == NULL)
--- a/usr/src/cmd/fs.d/autofs/autod_lookup.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/autofs/autod_lookup.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
 /*
  *	autod_lookup.c
  *
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -61,10 +60,6 @@
 	char *stack[STACKSIZ];
 	char **stkptr = stack;
 
-#ifdef lint
-	path = path;
-#endif /* lint */
-
 	/*
 	 * Default action is for no work to be done by kernel AUTOFS.
 	 */
--- a/usr/src/cmd/fs.d/autofs/autod_main.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/autofs/autod_main.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,7 +55,8 @@
 #include <rpcsvc/daemon_utils.h>
 #include <deflt.h>
 #include <strings.h>
-
+#include <priv.h>
+#include <tsol/label.h>
 
 static void autofs_prog(struct svc_req *, SVCXPRT *);
 static void autofs_mount_1_r(struct autofs_lookupargs *,
@@ -322,6 +322,14 @@
 	/* other initializations */
 	(void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL);
 
+	/* on a labeled system, the automounter implements read-down policy */
+	if (is_system_labeled()) {
+		if ((setpflags(NET_MAC_AWARE, 1) == -1) ||
+		    (setpflags(NET_MAC_AWARE_INHERIT, 1) == -1))
+			syslog(LOG_ERR, "ignored failure to set MAC-aware "
+			    "mode: %m");
+	}
+
 	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
 		syslog(LOG_ERR, "unable to set automatic MT mode");
 		exit(1);
--- a/usr/src/cmd/fs.d/autofs/autod_nfs.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/autofs/autod_nfs.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -81,6 +80,10 @@
 #include <net/if.h>
 #include <assert.h>
 #include <rpcsvc/daemon_utils.h>
+#include <pwd.h>
+#include <strings.h>
+#include <tsol/label.h>
+#include <zone.h>
 
 extern char *nfs_get_qop_name();
 extern AUTH *nfs_create_ah();
@@ -145,6 +148,8 @@
 	struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *,
 	bool_t, char *);
 
+static int create_homedir(const char *, const char *);
+
 enum type_of_stuff {
 	SERVER_ADDR = 0,
 	SERVER_PING = 1,
@@ -416,7 +421,6 @@
 	struct mapfs **mfs_tail)
 {
 	struct mapfs *tmp, *new;
-	void bcopy();
 
 	for (tmp = *mfs_head; tmp; tmp = tmp->mfs_next)
 		if ((strcmp(tmp->mfs_host, mfs->mfs_host) == 0 &&
@@ -1990,7 +1994,19 @@
 		    } /* syncaddr */
 		} /* AUTH_DH */
 
-		nfs_sec.sc_uid = cred->aup_uid;
+		/*
+		 * TSOL notes: automountd in tsol extension
+		 * has "read down" capability, i.e. we allow
+		 * a user to trigger an nfs mount into a lower
+		 * labeled zone. We achieve this by always having
+		 * root issue the mount request so that the
+		 * lookup ops can go past /zone/<zone_name>
+		 * on the server side.
+		 */
+		if (is_system_labeled())
+			nfs_sec.sc_uid = (uid_t)0;
+		else
+			nfs_sec.sc_uid = cred->aup_uid;
 		/*
 		 * If AUTH_DH is a chosen flavor now, its data will be stored
 		 * in the sec_data structure via nfs_clnt_secdata().
@@ -2253,7 +2269,7 @@
 		else
 			sl = service_list;
 
-		_check_services(sl);
+		(void) _check_services(sl);
 	}
 
 	/*
@@ -3598,6 +3614,13 @@
 			"  loopbackmount: fsname=%s, dir=%s, flags=%d\n",
 			fsname, dir, flags);
 
+	if (is_system_labeled()) {
+		if (create_homedir((const char *)fsname,
+		    (const char *)dir) == 0) {
+			return (NFSERR_NOENT);
+		}
+	}
+
 	if (mount(fsname, dir, flags | MS_DATA | MS_OPTIONSTR, fstype,
 	    NULL, 0, optbuf, sizeof (optbuf)) < 0) {
 		syslog(LOG_ERR, "Mount of %s on %s: %m", fsname, dir);
@@ -4214,3 +4237,78 @@
 
 	return (FALSE);
 }
+
+static int
+create_homedir(const char *src, const char *dst) {
+
+	struct stat stbuf;
+	char *dst_username;
+	struct passwd *pwd, pwds;
+	char buf_pwd[NSS_BUFLEN_PASSWD];
+	int homedir_len;
+	int dst_dir_len;
+	int src_dir_len;
+
+	if (trace > 1)
+		trace_prt(1, "entered create_homedir\n");
+
+	if (stat(src, &stbuf) == 0) {
+		if (trace > 1)
+			trace_prt(1, "src exists\n");
+		return (1);
+	}
+
+	dst_username = strrchr(dst, '/');
+	if (dst_username) {
+		dst_username++; /* Skip over slash */
+		pwd = getpwnam_r(dst_username, &pwds, buf_pwd,
+		    sizeof (buf_pwd));
+		if (pwd == NULL) {
+			return (0);
+		}
+	} else {
+		return (0);
+	}
+
+	homedir_len = strlen(pwd->pw_dir);
+	dst_dir_len = strlen(dst) - homedir_len;
+	src_dir_len = strlen(src) - homedir_len;
+
+	/* Check that the paths are in the same zone */
+	if (src_dir_len < dst_dir_len ||
+	    (strncmp(dst, src, dst_dir_len) != 0)) {
+		if (trace > 1)
+			trace_prt(1, "	paths don't match\n");
+		return (0);
+	}
+	/* Check that mountpoint is an auto_home entry */
+	if (dst_dir_len < 0 ||
+	    (strcmp(pwd->pw_dir, dst + dst_dir_len) != 0)) {
+		return (0);
+	}
+
+	/* Check that source is an home directory entry */
+	if (src_dir_len < 0 ||
+	    (strcmp(pwd->pw_dir, src + src_dir_len) != 0)) {
+		if (trace > 1)
+			trace_prt(1, "	homedir (2) doesn't match %s\n",
+		src+src_dir_len);
+		return (0);
+	}
+
+	if (mkdir(src,
+	    S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH) == -1) {
+		if (trace > 1) {
+			trace_prt(1, "	Couldn't mkdir %s\n", src);
+		}
+		return (0);
+	}
+
+	if (chown(src, pwd->pw_uid, pwd->pw_gid) == -1) {
+		unlink(src);
+		return (0);
+	}
+
+	/* Created new home directory for the user */
+	return (1);
+}
--- a/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,6 +50,9 @@
 #include <nfs/nfs_acl.h>
 #include <nfs/nfssys.h>
 #include <nfs/nfs4.h>
+#include <zone.h>
+#include <sys/socket.h>
+#include <tsol/label.h>
 
 /*
  * Determine valid semantics for most applications.
@@ -93,6 +95,8 @@
  */
 static	int	nofile_increase(int);
 static	int	reuseaddr(int);
+static	int	recvucred(int);
+static  int	anonmlp(int);
 static	void	add_to_poll_list(int, struct netconfig *);
 static	char	*serv_name_to_port_name(char *);
 static	int	bind_to_proto(char *, char *, struct netbuf **,
@@ -234,6 +238,7 @@
 	struct opthdr *opt;
 	char reqbuf[128];
 	bool_t use_any = FALSE;
+	bool_t gzone = TRUE;
 
 	if ((fd = nfslib_transport_open(nconf)) == -1) {
 		syslog(LOG_ERR, "cannot establish transport service over %s",
@@ -250,7 +255,7 @@
 		tb.addr.len = 0;
 		tb.addr.buf = 0;
 		use_any = TRUE;
-
+		gzone = (getzoneid() == GLOBAL_ZONEID);
 	} else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
 
 		syslog(LOG_ERR,
@@ -273,6 +278,31 @@
 			syslog(LOG_WARNING,
 			"couldn't set SO_REUSEADDR option on transport");
 		}
+	} else if (strcmp(nconf->nc_proto, "udp") == 0) {
+		/*
+		 * In order to run MLP on UDP, we need to handle creds.
+		 */
+		if (recvucred(fd) == -1) {
+			syslog(LOG_WARNING,
+			    "couldn't set SO_RECVUCRED option on transport");
+		}
+	}
+
+	/*
+	 * Make non global zone nfs4_callback port MLP
+	 */
+	if (use_any && is_system_labeled() && !gzone) {
+		if (anonmlp(fd) == -1) {
+			/*
+			 * failing to set this option means nfs4_callback
+			 * could fail silently later. So fail it with
+			 * with an error message now.
+			 */
+			syslog(LOG_ERR,
+			    "couldn't set SO_ANON_MLP option on transport");
+			(void) t_close(fd);
+			return (-1);
+		}
 	}
 
 	if (nconf->nc_semantics == NC_TPI_CLTS)
@@ -364,29 +394,26 @@
 }
 
 static int
-reuseaddr(int fd)
+setopt(int fd, int level, int name, int value)
 {
 	struct t_optmgmt req, resp;
-	struct opthdr *opt;
-	char reqbuf[128];
-	int *ip;
+	struct {
+		struct opthdr opt;
+		int value;
+	} reqbuf;
 
-	/* LINTED pointer alignment */
-	opt = (struct opthdr *)reqbuf;
-	opt->level = SOL_SOCKET;
-	opt->name = SO_REUSEADDR;
-	opt->len = sizeof (int);
+	reqbuf.opt.level = level;
+	reqbuf.opt.name = name;
+	reqbuf.opt.len = sizeof (int);
 
-	/* LINTED pointer alignment */
-	ip = (int *)&reqbuf[sizeof (struct opthdr)];
-	*ip = 1;
+	reqbuf.value = value;
 
 	req.flags = T_NEGOTIATE;
-	req.opt.len = sizeof (struct opthdr) + opt->len;
-	req.opt.buf = (char *)opt;
+	req.opt.len = sizeof (reqbuf);
+	req.opt.buf = (char *)&reqbuf;
 
 	resp.flags = 0;
-	resp.opt.buf = reqbuf;
+	resp.opt.buf = (char *)&reqbuf;
 	resp.opt.maxlen = sizeof (reqbuf);
 
 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
@@ -396,6 +423,24 @@
 	return (0);
 }
 
+static int
+reuseaddr(int fd)
+{
+	return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
+}
+
+static int
+recvucred(int fd)
+{
+	return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
+}
+
+static int
+anonmlp(int fd)
+{
+	return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
+}
+
 void
 nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
 {
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -112,6 +112,7 @@
 	int maxthreads;
 	int maxrecsz = RPC_MAXDATASIZE;
 	bool_t exclbind = TRUE;
+	bool_t can_do_mlp;
 
 	/*
 	 * Mountd requires uid 0 for:
@@ -123,10 +124,13 @@
 	 *		auditing
 	 *		nfs syscall
 	 *		file dac search (so it can stat all files)
+	 *	Optional privileges:
+	 *		MLP
 	 */
+	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
-		    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
-		    (char *)NULL) == -1) {
+	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
+	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 		(void) fprintf(stderr,
 			"%s must be run as with sufficient privileges\n",
 			argv[0]);
@@ -788,6 +792,19 @@
 	}
 
 	/*
+	 * Trusted Extension doesn't support older versions of nfs(v2, v3).
+	 * To prevent circumventing TX label policy via using an older
+	 * version of nfs client, reject the mount request and log an
+	 * error.
+	 */
+	if (is_system_labeled()) {
+		syslog(LOG_ERR,
+		    "mount rejected: Solaris TX only supports nfs4 clients");
+		error = EACCES;
+		goto reply;
+	}
+
+	/*
 	 * Get the real path (no symbolic links in it)
 	 */
 	if (realpath(path, rpath) == NULL) {
--- a/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -137,6 +136,7 @@
 	NETSELDECL(df_proto) = NULL;
 	NETSELPDECL(providerp);
 	char *defval;
+	boolean_t can_do_mlp;
 
 	MyName = *av;
 
@@ -146,8 +146,10 @@
 	(void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID);
 	svcsetprio();
 
+	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
-	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, (char *)NULL) == -1) {
+	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS,
+	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 		(void) fprintf(stderr, "%s should be run with"
 			" sufficient privileges\n", av[0]);
 		exit(1);
--- a/usr/src/cmd/fs.d/nfs/statd/sm_svc.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/statd/sm_svc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -671,9 +670,10 @@
  */
 
 static void
-set_statmon_owner()
+set_statmon_owner(void)
 {
 	int i;
+	boolean_t can_do_mlp;
 
 	/*
 	 * Recursively chown/chgrp /var/statmon and the alternate paths,
@@ -687,8 +687,10 @@
 		one_statmon_owner(alt_path);
 	}
 
+	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
-	    DAEMON_UID, DAEMON_GID, (char *)NULL) == -1) {
+	    DAEMON_UID, DAEMON_GID, can_do_mlp ? PRIV_NET_BINDMLP : NULL,
+	    NULL) == -1) {
 		syslog(LOG_ERR, "can't run unprivileged: %m");
 		exit(1);
 	}
--- a/usr/src/cmd/ldap/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -1,3 +1,23 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -33,7 +53,7 @@
 
 # ldapaddent command
 LDAPADDENTPROG=	ldapaddent
-LDAPADDENTSRCS=	ldapaddent.c ldapaddrbac.c
+LDAPADDENTSRCS=	ldapaddent.c ldapaddrbac.c ldapaddtsol.c
 LDAPADDENTOBJS=	$(LDAPADDENTSRCS:%.c=%.o)
 
 # ldapclient command
@@ -74,7 +94,7 @@
 lint:=          TARGET= lint
 
 # C Pre-Processor flags used by C, CC & lint
-CPPFLAGS +=	-DSUN -DSVR4 -D_SYS_STREAM_H -DSOLARIS_LDAP_CMD \
+CPPFLAGS +=	-DSUN -DSVR4 -DSOLARIS_LDAP_CMD \
 		-I ../../../lib/libldap5/include/ldap \
 		-I ../../../lib/libsldap/common \
 		-I ../../../lib/libnsl/include/rpcsvc \
@@ -87,7 +107,7 @@
 ldapdelete :=	LDLIBS += -lldap
 ldapmodify :=	LDLIBS += -lldap
 ldaplist :=	LDLIBS += -lsldap
-ldapaddent :=	LDLIBS += -lsldap -lnsl
+ldapaddent :=	LDLIBS += -lsldap -lnsl -lsecdb
 ldapclient :=	LDLIBS += -lsldap -lscf
 
 lint :=		LDLIBS += -lldap
--- a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh	Fri Mar 24 12:29:20 2006 -0800
@@ -1,11 +1,12 @@
 #!/bin/sh
 #
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -21,11 +22,9 @@
 # CDDL HEADER END
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # idsconfig -- script to setup iDS 5.x for Native LDAP II.
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -3146,6 +3145,8 @@
 attributetypes:( 1.3.6.1.4.1.42.2.27.5.1.63 NAME 'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. "Solaris" specifies a Solaris print server extension. The value is represented by the following value: server "," destination ", Solaris".' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
 attributetypes:( 1.3.6.1.4.1.42.2.27.5.1.64 NAME 'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key "=" value.' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.57 NAME 'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributetypes:( 1.3.6.1.4.1.42.2.27.5.1.67 NAME 'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributetypes:( 1.3.6.1.4.1.42.2.27.5.1.68 NAME 'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 EOF
 ) > ${TMPDIR}/schema_attr
 
@@ -3291,6 +3292,16 @@
 changetype: modify
 add: objectclasses
 objectclasses:	( 1.3.6.1.4.1.42.2.27.5.2.12 NAME 'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST ( cn ) MAY ( nisplusTimeZone $ description ) )
+
+dn: cn=schema
+changetype: modify
+add: objectclasses
+objectclasses:  ( 1.3.6.1.4.1.42.2.27.5.2.8 NAME 'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP 'top' MUST ( objectclass $ ipTnetTemplateName ) MAY ( SolarisAttrKeyValue ) )
+
+dn: cn=schema
+changetype: modify
+add: objectclasses
+objectclasses:	( 1.3.6.1.4.1.42.2.27.5.2.9 NAME 'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP 'top' AUXILIARY MUST ( objectclass $ ipTnetNumber ) )
 EOF
 ) > ${TMPDIR}/schema_obj
 
@@ -3612,7 +3623,7 @@
 
     for ou in people group rpc protocols networks netgroup \
 	aliases hosts services ethers profile printers \
-	SolarisAuthAttr SolarisProfAttr Timezone ; do
+	SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do
 
 	# Check if nismaps already exist.
 	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=${ou},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
--- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -3572,6 +3572,10 @@
 		filedbmline_comment, "SolarisAuthAttr" },
 	{ NS_LDAP_TYPE_AUUSER, genent_audit_user, dump_audit_user,
 		filedbmline_comment, "SolarisAuditUser" },
+	{ NS_LDAP_TYPE_TNRHDB, genent_tnrhdb, dump_tnrhdb,
+		filedbmline_comment, "ipTnetHost" },
+	{ NS_LDAP_TYPE_TNRHTP, genent_tnrhtp, dump_tnrhtp,
+		filedbmline_comment, "ipTnetTemplate" },
 	{ 0, 0, 0, 0, 0 }
 };
 
@@ -3641,9 +3645,17 @@
 		(void) snprintf(filter, sizeof (filter),
 		    "(&(objectclass=%s)(!(objectclass=SolarisExecAttr)))",
 		    tt->objclass);
-	} else
+	} else if (strcmp(tt->ttype, NS_LDAP_TYPE_TNRHDB) == 0) {
+		/*
+		 * tnrhtp entries are ipTnet entries with SolarisAttrKeyValue
+		 */
+		(void) snprintf(filter, sizeof (filter),
+		    "(&(objectclass=%s)(SolarisAttrKeyValue=*)))",
+		    tt->objclass);
+	} else {
 		(void) snprintf(filter, sizeof (filter),
 		    "(objectclass=%s)", tt->objclass);
+	}
 
 	if (flags & F_VERBOSE)
 		(void) fprintf(stdout, gettext("FILTER = %s\n"), filter);
--- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -76,11 +75,16 @@
 extern int genent_exec_attr(char *line, int (*cback)());
 extern int genent_auth_attr(char *line, int (*cback)());
 extern int genent_audit_user(char *line, int (*cback)());
+extern int genent_tnrhdb(char *line, int (*cback)());
+extern int genent_tnrhtp(char *line, int (*cback)());
+
 extern void dump_user_attr(ns_ldap_result_t *res);
 extern void dump_prof_attr(ns_ldap_result_t *res);
 extern void dump_exec_attr(ns_ldap_result_t *res);
 extern void dump_auth_attr(ns_ldap_result_t *res);
 extern void dump_audit_user(ns_ldap_result_t *res);
+extern void dump_tnrhdb(ns_ldap_result_t *res);
+extern void dump_tnrhtp(ns_ldap_result_t *res);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,7 +65,7 @@
  * genent_attr:
  *   Generic function for generating entries for all of the *_attr databases.
  */
-static int
+int
 genent_attr(
 	char	*line,		/* entry to parse */
 	int	ncol,		/* number of columns in the database */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/ldap/ns_ldap/ldapaddtsol.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,142 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ldapaddtsol.c
+ *
+ * Routines to add tnrhdb and tnrhtp from /etc/security/tsol into LDAP.
+ * Can also be used to dump entries from a ldap container in /etc format.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <string.h>
+#include <nss.h>
+#include <secdb.h>
+#include <sys/tsol/tndb.h>
+#include "ldapaddent.h"
+
+extern  int	genent_attr(char *, int, entry_col **);
+
+int
+genent_tnrhdb(char *line, int (*cback)())
+{
+	entry_col	*ecol;
+	tsol_rhstr_t	data;
+	int		res, retval;
+
+	/*
+	 * parse entry into columns
+	 */
+	res = genent_attr(line, TNRHDB_NCOL, &ecol);
+	if (res != GENENT_OK)
+		return (res);
+
+	data.address = _do_unescape(ecol[0].ec_value.ec_value_val);
+	data.template = ecol[1].ec_value.ec_value_val;
+	if (strchr(data.address, ':') == NULL)
+		data.family = AF_INET;
+	else
+		data.family = AF_INET6;
+
+	if (flags & F_VERBOSE)
+		(void) printf(gettext("Adding entry : %s\n"), data.address);
+
+	retval = (*cback)(&data, 1);
+	if (retval)
+		res = GENENT_CBERR;
+
+	free(ecol);
+
+	return (res);
+}
+
+void
+dump_tnrhdb(ns_ldap_result_t *res)
+{
+	char	**value = NULL;
+
+	value = __ns_ldap_getAttr(res->entry, "ipTnetNumber");
+	if (value && value[0])
+		(void) printf("%s", value[0]);
+	else
+		return;
+
+	(void) putchar(':');
+	value = __ns_ldap_getAttr(res->entry, "ipTnetTemplateName");
+	if (value && value[0])
+		(void) printf("%s", value[0]);
+	(void) putchar('\n');
+}
+
+int
+genent_tnrhtp(char *line, int (*cback)())
+{
+	entry_col	*ecol;
+	tsol_tpstr_t	data;
+	int		res, retval;
+
+	/*
+	 * parse entry into columns
+	 */
+	res = genent_attr(line, TNRHTP_NCOL, &ecol);
+	if (res != GENENT_OK)
+		return (res);
+
+	data.template = ecol[0].ec_value.ec_value_val;
+	data.attrs = ecol[1].ec_value.ec_value_val;
+
+	if (flags & F_VERBOSE)
+		(void) printf(gettext("Adding entry : %s\n"), data.template);
+
+	retval = (*cback)(&data, 1);
+	if (retval)
+		res = GENENT_CBERR;
+
+	free(ecol);
+
+	return (res);
+}
+
+void
+dump_tnrhtp(ns_ldap_result_t *res)
+{
+	char	**value = NULL;
+
+	value = __ns_ldap_getAttr(res->entry, "ipTnetTemplateName");
+	if (value && value[0])
+		(void) printf("%s", value[0]);
+	else
+		return;
+
+	(void) putchar(':');
+	value = __ns_ldap_getAttr(res->entry, "SolarisAttrKeyValue");
+	if (value && value[0])
+		(void) printf("%s", value[0]);
+	(void) putchar('\n');
+}
--- a/usr/src/cmd/ldap/ns_ldap/mapping.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ldap/ns_ldap/mapping.c	Fri Mar 24 12:29:20 2006 -0800
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -29,6 +30,7 @@
 #include <libintl.h>
 #include <strings.h>
 #include <stdio.h>
+#include <tsol/label.h>
 #include "../../../lib/libsldap/common/ns_sldap.h"
 
 
@@ -67,6 +69,8 @@
 	{"exec_attr", "cn", "SolarisExecAttr", NULL},
 	{"user_attr", "uid", "SolarisUserAttr", NULL},
 	{"audit_user", "uid", "SolarisAuditUser", NULL},
+	{"tnrhtp", "ipTnetTemplateName", "ipTnetTemplate", NULL},
+	{"tnrhdb", "ipTnetNumber", "ipTnetHost", NULL},
 	{NULL, NULL, NULL, NULL}
 };
 
@@ -112,10 +116,20 @@
 		"automountMapName",
 		"automountMap");
 	for (i = 0; maplist[i].database != NULL; i++) {
-	/* skip printing shadow */
-	if (strcasecmp(maplist[i].database, "shadow") != 0)
+		/* skip printing shadow */
+		if (strcasecmp(maplist[i].database, "shadow") == 0)
+			continue;
+		if (!is_system_labeled()) {
+			/*
+			 * do not print tnrhdb and tnrhtp if system is
+			 * not configured with Trusted Extensions
+			 */
+			if ((strcasecmp(maplist[i].database, "tnrhdb") == 0) ||
+			    (strcasecmp(maplist[i].database, "tnrhtp") == 0))
+				continue;
+		}
 		(void) fprintf(stdout, "%-15s%-20s%s\n", maplist[i].database,
-			maplist[i].def_type, maplist[i].objectclass);
+		    maplist[i].def_type, maplist[i].objectclass);
 	}
 }
 
--- a/usr/src/cmd/lp/cmd/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,11 +17,13 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/lp/cmd/Makefile
@@ -69,12 +70,14 @@
 cancel:=	LDLIBS += $(LIBREQ) $(LIBMSG) $(LIBOAM) $(LIBLP)
 lp:=		LDLIBS += $(LIBPRT) $(LIBREQ) $(LIBMSG) $(LIBOAM) $(LIBLP)
 lpfilter:=	LDLIBS += $(LIBFLT) $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBLP) \
-			-lgen
+			-lgen -z lazyload -lsecdb -z nolazyload
 lpforms:=	LDLIBS += $(LIBFRM) $(LIBMSG) $(LIBREQ) $(LIBOAM) \
-		$(LIBACC) $(LIBLP)
+			$(LIBACC) $(LIBLP) \
+			-z lazyload -lsecdb -z nolazyload
 lpmove:=	LDLIBS += $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBLP)
 lpshut:=	LDLIBS += $(LIBMSG) $(LIBOAM) $(LIBLP)
-lpsystem:=	LDLIBS += $(LIBSYS) $(LIBMSG) $(LIBOAM) $(LIBLP) -lnsl
+lpsystem:=	LDLIBS += $(LIBSYS) $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBLP) \
+			-lnsl -z lazyload -lsecdb -z nolazyload
 lpusers:=	LDLIBS += $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBUSR) $(LIBLP)
 
 .KEEP_STATE:
--- a/usr/src/cmd/lp/cmd/adaptor/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 1996-2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -38,7 +39,7 @@
 
 CPPFLAGS +=	-I$(LPINC)
 CPPFLAGS +=	-I$(SRC)/lib
-LDLIBS +=	-lprint -lc
+LDLIBS +=	-lprint -z lazyload -ltsol -z nolazyload -lc
 LDLIBS	+=	-L$(SRC)/cmd/lp/lib/msgs -llpmsg
 LDLIBS	+=	-L$(SRC)/cmd/lp/lib/class -llpcls
 LDLIBS	+=	-L$(SRC)/cmd/lp/lib/lp -llp
--- a/usr/src/cmd/lp/cmd/adaptor/cancel_job.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/cancel_job.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -83,7 +82,6 @@
 	return (buf);
 }
 
-
 /*
  * lpsched_cancel_job() attempts to cancel an lpsched requests that match the
  * passed in criteria.  a message is written for each cancelation or
@@ -123,12 +121,12 @@
 		size_t	size;
 		time_t	date;
 		short	outcome;
-		char *dest, *form, *pwheel, *file, *owner, *reqid;
+		char *dest, *slabel, *form, *pwheel, *file, *owner, *reqid;
 		const char **list_ptr = list;
 		char buf[BUFSIZ];
 
-		if (rcv_msg(R_INQUIRE_REQUEST, &status, &reqid, &owner, &size,
-				&date, &outcome, &dest, &form, &pwheel,
+		if (rcv_msg(R_INQUIRE_REQUEST, &status, &reqid, &owner, &slabel,
+				&size, &date, &outcome, &dest, &form, &pwheel,
 				&file) < 0) {
 			fprintf(ofp,
 			gettext("Failure to communicate with lpsched\n"));
--- a/usr/src/cmd/lp/cmd/adaptor/misc.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/misc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,6 +38,8 @@
 
 #include <syslog.h>
 
+#include <tsol/label.h>
+
 #include "misc.h"
 
 /* lpsched include files */
@@ -48,7 +49,6 @@
 
 static char Msg[MSGMAX];
 
-
 /*
  * Format and send message to lpsched
  * (die if any errors occur)
@@ -216,15 +216,32 @@
  * has access to communicate with the scheduler.  In Solaris this currently
  * has no meaning.  The host is automatically allowed access.
  */
+char *slabel = NULL;
+
 int
-lpsched_client_access(const char *printer, const char *host)
+lpsched_client_access(const char *printer, const char *host, int peerfd)
 {
-	syslog(LOG_DEBUG, "lpsched_client_access(%s, %s)",
-		(printer ? printer : "NULL"), (host ? host : "NULL"));
+	syslog(LOG_DEBUG, "lpsched_client_access(%s, %s, %d)",
+		(printer ? printer : "NULL"), (host ? host : "NULL"),
+		peerfd);
 
 	if ((printer == NULL) || (host == NULL))
 		return (-1);
 
+	if (is_system_labeled) {
+		short status = MOK;
+		extern MESG *lp_Md;	/* liblpmsg supplies this */
+
+		if ((snd_msg(S_PASS_PEER_CONNECTION) < 0) ||
+		    (ioctl(lp_Md->writefd, I_SENDFD, peerfd) < 0) ||
+		    (rcv_msg(R_PASS_PEER_CONNECTION, &status) < 0))
+			status = MTRANSMITERR;
+		if (status != MOK)
+			return (-1);
+
+		get_peer_label(peerfd, &slabel);
+	}
+
 	return (0);
 }
 
--- a/usr/src/cmd/lp/cmd/adaptor/misc.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/misc.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1996, by Sun Microsystems, Inc.
- * All Rights Reserved
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -34,5 +33,6 @@
 extern int id_no(const char *);
 extern char *user_name(const char *);
 extern char *user_host(const char *);
+extern char *slabel;
 
 #endif /* _MISC_H */
--- a/usr/src/cmd/lp/cmd/adaptor/show_queue.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/show_queue.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1995-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -160,8 +159,8 @@
 #define	HEADER gettext("Rank\tOwner\tJob\tFile(s)\t\t\t\tTotal Size\n")
 
 static int
-job_list(const char *printer, FILE *ofp, const int type, const char **list,
-		const char *status_message, int *rank)
+job_list(const char *printer, FILE *ofp, const int type,
+    const char **list, const char *status_message, int *rank)
 {
 	int count = 0;
 	short status, outcome;
@@ -173,10 +172,11 @@
 		size_t size;
 		time_t date;
 		int id;
-		char *user, *reqid, *owner, *dest, *form, *pwheel, *file, *host;
+		char *user, *slabel, *reqid, *owner, *dest, *form, *pwheel,
+			*file, *host;
 
-		if (rcv_msg(R_INQUIRE_REQUEST, &status, &reqid, &owner, &size,
-				&date, &outcome, &dest, &form, &pwheel,
+		if (rcv_msg(R_INQUIRE_REQUEST, &status, &reqid, &owner, &slabel,
+				&size, &date, &outcome, &dest, &form, &pwheel,
 				&file) < 0)
 			return (count);
 
@@ -215,6 +215,7 @@
 	return (count);
 }
 
+
 /*
  * lpsched_show_queue() attempts to display the queue of "pending" jobs.  The
  * "type" is used to determine if this should be a short or long format
--- a/usr/src/cmd/lp/cmd/adaptor/submit_job.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/adaptor/submit_job.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1995-1999,2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,15 +30,21 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <sys/types.h>
+#include <sys/zone.h>
 #include <string.h>
 #include <libintl.h>
 
 #include <syslog.h>
 #include <stdarg.h>
 
+#include <tsol/label.h>
+
 #include "misc.h"
 
 /* lpsched include files */
+#if defined PS_FAULTED
+#undef  PS_FAULTED
+#endif /* PS_FAULTED */
 #include "lp.h"
 #include "msgs.h"
 #include "printers.h"
@@ -85,11 +90,11 @@
 	}
 }
 
-
 /*
  * mail() will send a mail message to the requesting user in the event of an
  * error during job submission.
  */
+
 static void
 mail(REQUEST *request, char *req_file, char *fmt, ...)
 {
@@ -97,6 +102,7 @@
 	char buf[BUFSIZ];
 	char *uname;
 	va_list ap;
+	char	*mail_zonename = NULL;
 
 	/*
 	 * Clean-up user name so we don't pass flags to /bin/mail, or
@@ -110,27 +116,59 @@
 	if (*uname == '\0')
 		return;		/* No username found */
 
-	snprintf(buf, sizeof (buf), "/bin/mail %s", uname);
+	/*
+	 * If in the global zone and the system is labeled, mail is
+	 * handled via a local labeled zone that is the same label as the
+	 * request.
+	 */
+	if ((getzoneid() == GLOBAL_ZONEID) && is_system_labeled() &&
+	    slabel != NULL) {
+		if ((mail_zonename = get_labeled_zonename(slabel)) ==
+		    (char *)-1) {
+			/* error during get_labeled_zonename, just return */
+			return;
+		}
+	}
+
+	/*
+	 * If mail_zonename is not NULL, use zlogin to execute /bin/mail
+	 * in the labeled zone 'mail_zonename'.
+	 */
+
+	if (mail_zonename != NULL) {
+		syslog(LOG_DEBUG,
+		    "lpsched: using '/usr/sbin/zlogin %s /bin/mail %s' to mail",
+		    mail_zonename, uname);
+		snprintf(buf, sizeof (buf),
+		    "/usr/sbin/zlogin %s /bin/mail %s",
+		    mail_zonename, uname);
+		Free(mail_zonename);
+	} else {
+		syslog(LOG_DEBUG,
+		    "lpsched: using '/bin/mail %s' to mail",
+		    uname);
+		snprintf(buf, sizeof (buf), "/bin/mail %s", uname);
+	}
 	clean_string(buf);
 	if ((pp = popen(buf, "w+")) == NULL)
 		return;
 	fprintf(pp, gettext("Subject: print request for %s failed\n\n"),
-		request->destination);
+	    request->destination);
 
 	fprintf(pp, gettext("\n\tRequest File: %s"), req_file);
 	fprintf(pp, gettext("\n\tDocument Type: %s"),
-		(request->input_type ? request->input_type :
-			gettext("(unknown)")));
+	    (request->input_type ? request->input_type :
+	    gettext("(unknown)")));
 	fprintf(pp, gettext("\n\tTitle:\t%s"),
-		(request->title ? request->title : gettext("(none)")));
+	    (request->title ? request->title : gettext("(none)")));
 	fprintf(pp, gettext("\n\tCopies:\t%d"), request->copies);
 	fprintf(pp, gettext("\n\tPriority:\t%d"), request->priority);
 	fprintf(pp, gettext("\n\tForm:\t%s"),
-		(request->form ? request->form : gettext("(none)")));
+	    (request->form ? request->form : gettext("(none)")));
 	fprintf(pp, gettext("\n\tOptions:\t%s"),
-		(request->options ? request->options : gettext("(none)")));
+	    (request->options ? request->options : gettext("(none)")));
 	fprintf(pp, gettext("\n\tModes:\t%s"),
-		(request->modes ? request->modes : gettext("(none)")));
+	    (request->modes ? request->modes : gettext("(none)")));
 
 	fprintf(pp, gettext("\n\tReason for Failure:\n\n\t\t"));
 	va_start(ap, fmt);
@@ -505,7 +543,7 @@
 	char	buf[MAXPATHLEN];
 	int	file_no = 0;
 	int	rc = -1;
-	char 	*tmp_dir = (char *)lpsched_temp_dir(printer, host);
+	char 	*tmp_dir;
 	char  *tmp;
 	short status;
 	long  bits;
@@ -515,6 +553,8 @@
 	syslog(LOG_DEBUG, "lpsched_submit_job(%s, %s, 0x%x)",
 		(printer ? printer : "NULL"), (cf ? cf : "NULL"), df_list);
 
+	tmp_dir = (char *)lpsched_temp_dir(printer, host);
+
 	if ((printer == NULL) || (host == NULL) || (cf == NULL) ||
 	    (df_list == NULL))
 		return (-1);
@@ -558,18 +598,21 @@
 	secure.req_id = strdup(buf);
 	secure.uid = LP_UID;
 	secure.gid = 0;
+	secure.slabel = NULL;
 
 	/* save the request file */
 	snprintf(buf, sizeof (buf), "%s/%d-0", host, request_id);
 	if (putrequest(buf, request) < 0) {
-		mail(request, buf, gettext("Can't save print request"));
+		mail(request, buf,
+		    gettext("Can't save print request"));
 		unlink_files(request->file_list);
 		return (-1);
 	}
 
 	/* save the secure file */
 	if (putsecure(buf, &secure) < 0) {
-		mail(request, buf, gettext("Can't save print secure file"));
+		mail(request, buf,
+		    gettext("Can't save print secure file"));
 		snprintf(buf, sizeof (buf), "%s/%s/%d-0", Lp_Tmp, host,
 		    request_id);
 		unlink(buf);
@@ -624,7 +667,8 @@
 				gettext("failure to communicate with lpsched"));
 			break;
 		default:
-			mail(request, buf, gettext("Unknown error: %d"),
+			mail(request, buf,
+			    gettext("Unknown error: %d"),
 				status);
 			break;
 		}
--- a/usr/src/cmd/lp/cmd/lpadmin/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpadmin/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,13 +17,15 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
 # cmd/lp/cmd/lpadmin/Makefile
 #
 
@@ -65,7 +66,8 @@
 
 SYSLIBS=	-lcurses
 
-LDLIBS +=	$(LPLIBS) $(SYSLIBS) $(I18N)
+LDLIBS +=	-z lazyload -lsecdb -z nolazyload $(LPLIBS) \
+			$(SYSLIBS) $(I18N)
 
 PROG=		lpadmin
 
--- a/usr/src/cmd/lp/cmd/lpadmin/do_printer.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_printer.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -24,7 +23,7 @@
 
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,11 +34,16 @@
 #include <errno.h>
 #include <limits.h>
 #include <sys/types.h>
+#include <sys/zone.h>
 #include <stdlib.h>
 #include <libintl.h>
-
+#include <sys/tsol/label_macro.h>
+#include <bsm/devices.h>
 #include "lp.h"
 #include "class.h"
+#if defined PS_FAULTED
+#undef	PS_FAULTED
+#endif
 #include "printers.h"
 #include "msgs.h"
 
@@ -59,9 +63,11 @@
 #endif
 
 extern char		*label;
+
 static void		configure_printer();
 static char		*fullpath();
 char			*nameit();
+static void		pack_white(char *ptr);
 
 /**
  ** do_printer() - CREATE OR CHANGE PRINTER
@@ -630,6 +636,11 @@
 				);
 			done(1);
 		}
+
+		if ((getzoneid() == GLOBAL_ZONEID) && system_labeled &&
+		    (prbufp->device != NULL))
+			update_dev_dbs(p, prbufp->device, "ADD");
+
 	END_CRITICAL
 
 	return;
@@ -683,3 +694,88 @@
 	(void) strcat (copy, nm);
 	return (copy);
 }
+
+/*
+ * update_dev_dbs - ADD/REMOVE ENTRIES FOR THE PRINTER IN DEVICE
+ * 			ALLOCATION FILES
+ *
+ * We intentionally ignore errors, since we don't want the printer
+ * installation to be viewed as failing just because we didn't add
+ * the device_allocate entry.
+ *
+ *	Input:
+ *		prtname - printer name
+ *		devname - device associated w/ this printer
+ *		func - [ADD|REMOVE] entries in /etc/security/device_allocate
+ *			and /etc/security/device_maps
+ *
+ *	Return:
+ *		Always 'quiet' return.  Failures are ignored.
+ */
+void
+update_dev_dbs(char *prtname, char *devname, char *func)
+{
+	int		fd, status;
+	pid_t		pid;
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		/* fork failed, just return quietly */
+		return;
+	case 0:
+		/* child */
+		/* redirect to /dev/null */
+		(void) close(1);
+		(void) close(2);
+		fd = open("/dev/null", O_WRONLY);
+		fd = dup(fd);
+
+		if (strcmp(func, "ADD") == 0) {
+			execl("/usr/sbin/add_allocatable", "add_allocatable",
+			    "-n", prtname, "-t", "lp", "-l", devname,
+			    "-o", "minlabel=admin_low:maxlabel=admin_high",
+			    "-a", "*", "-c", "/bin/true", NULL);
+		} else {
+			if (strcmp(func, "REMOVE") == 0) {
+				execl("/usr/sbin/remove_allocatable",
+				    "remove_allocatable", "-n", prtname, NULL);
+			}
+		}
+		_exit(1);
+		/* NOT REACHED */
+	default:
+		waitpid(pid, &status, 0);
+		return;
+	}
+}
+
+/*
+ * pack_white(ptr) trims off multiple occurances of white space from a NULL
+ * terminated string pointed to by "ptr".
+ */
+static void
+pack_white(char *ptr)
+{
+	char	*tptr;
+	char	*mptr;
+	int	cnt;
+
+	if (ptr == NULL)
+		return;
+	cnt = strlen(ptr);
+	if (cnt == 0)
+		return;
+	mptr = (char *)calloc((unsigned)cnt+1, sizeof (char));
+	if (mptr == NULL)
+		return;
+	tptr = strtok(ptr, " \t");
+	while (tptr != NULL) {
+		(void) strcat(mptr, tptr);
+		(void) strcat(mptr, " ");
+		tptr = strtok(NULL, " \t");
+	}
+	cnt = strlen(mptr);
+	(void) strcpy(ptr, mptr);
+	free(mptr);
+}
--- a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,6 +27,11 @@
 /*	  All Rights Reserved  	*/
 
 
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include "stdio.h"
@@ -55,6 +59,8 @@
 			chkopts3(),
 			exit();
 
+int			system_labeled = 0;
+
 int			scheduler_active = 0;
 
 char			*label = 0;
@@ -88,6 +94,8 @@
 		/*NOTREACHED*/
 	}
 
+	system_labeled = is_system_labeled();
+
 	uname(&un);
 	Local_System = strdup(un.nodename);
     
--- a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -24,7 +23,7 @@
 
 
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -126,6 +125,10 @@
 			startup(),
 			usage();
 
+/* Routines/variables needed for labeled systems */
+extern void		update_dev_dbs(char *, char *, char *);
+extern int		system_labeled;
+
 
 #if	defined(__STDC__)
 void			send_message( int , ... );
--- a/usr/src/cmd/lp/cmd/lpadmin/rmdest.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpadmin/rmdest.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,12 @@
 /*	  All Rights Reserved  	*/
 
 
-#ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1	*/
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #include "stdio.h"
 #include "ctype.h"
@@ -103,6 +107,9 @@
 		if (STREQU(getdflt(), dest))
 			newdflt (NAME_NONE);
 
+		if (system_labeled) {
+			update_dev_dbs(dest, NULL, "REMOVE");
+		}
 		break;
 
 	case MBUSY:
--- a/usr/src/cmd/lp/cmd/lpc/process.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpc/process.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -319,6 +318,7 @@
 		*reject_reason,
 		*request_id,
 		*form,
+		*slabel,
 		*file,
 		*char_set,
 		*disable_reason;
@@ -366,6 +366,7 @@
 		rcv_msg(R_INQUIRE_REQUEST_RANK, &status,
 					   &request_id,
 					   &user,
+					   &slabel,
 					   &size,
 					   &date,
 					   &state,
--- a/usr/src/cmd/lp/cmd/lpc/topq.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpc/topq.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -171,7 +170,7 @@
 char	*machine;
 #endif
 {
-	char	 *request_id, *form, *character_set;
+	char	 *request_id, *form, *slabel, *character_set;
 	char	  buf[50];
 	char	**rqlist = NULL, **pp;
 	short	  state, status;
@@ -188,6 +187,7 @@
 		rcv_msg(R_INQUIRE_REQUEST, &status,
 					   &request_id,
 					   &user,
+					   &slabel,
 					   &size,
 					   &date,
 					   &state,
--- a/usr/src/cmd/lp/cmd/lpsched/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,11 +17,13 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/lp/cmd/lpsched/lpsched/Makefile
@@ -102,7 +103,8 @@
 		$(LIBLP)	\
 		$(LIBSEC)
 
-SYSLIBS=	-lcurses -lgen -lcurses -lnsl
+SYSLIBS=	-lcurses -lgen -lcurses -lnsl -z lazyload \
+		-ltsol -lsecdb -lcmd -lbsm -z nolazyload
 
 LDLIBS +=	$(LPLIBS) $(SYSLIBS)
 
--- a/usr/src/cmd/lp/cmd/lpsched/disp1.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/disp1.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -145,6 +144,8 @@
 		rp->secure->req_id = Strdup(s->req_id);
 		rp->secure->user = Strdup(s->user);
 		rp->secure->system = Strdup(s->system);
+		if (md->slabel != NULL)
+			rp->secure->slabel = Strdup(md->slabel);
 		freesecure(s);
 		/*
 		**  There are some anomallies associated w/
@@ -160,6 +161,8 @@
 		rp->request->outcome = 0;
 		rp->secure->uid = md->uid;
 		rp->secure->gid = md->gid;
+		if (md->slabel != NULL)
+			rp->secure->slabel = Strdup(md->slabel);
     
 		pw = getpwuid(md->uid);
 		endpwent();
@@ -365,6 +368,10 @@
     
     if (!(rp = request_by_id(req_id)))
 	status = MUNKNOWN;
+    else if ((md->admin == 0) && (is_system_labeled()) &&
+	    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+	    (!STREQU(md->slabel, rp->secure->slabel)))
+	status = MUNKNOWN;
     else if (rp->request->outcome & RS_DONE)
 	status = M2LATE;
     else if (!md->admin && md->uid != rp->secure->uid)
@@ -438,6 +445,10 @@
 
     if (!(rp = request_by_id(req_id)))
 	status = MUNKNOWN;
+    else if ((md->admin == 0) && (is_system_labeled()) &&
+	    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+	    (!STREQU(md->slabel, rp->secure->slabel)))
+	status = MUNKNOWN;
     else if (!(rp->request->outcome & RS_CHANGING))
 	status = MNOSTART;
     else {
@@ -618,6 +629,15 @@
 	    return(Strdup(crp->secure->req_id));
 	}
 
+	/*
+	 * For Trusted Extensions, we need to check the sensitivity label of the
+	 * connection and job before we try to cancel it.
+	 */
+	if ((md->admin == 0) && (is_system_labeled()) &&
+	    (md->slabel != NULL) && (crp->secure->slabel != NULL) &&
+	    (!STREQU(md->slabel, crp->secure->slabel)))
+	    continue;
+
 	crp->reason = MOK;
 	creq_id = Strdup(crp->secure->req_id);
 
@@ -737,14 +757,23 @@
 
 	if (*pwheel && !SAME(pwheel, rp->pwheel_name))
 	    continue;
+
+	/*
+	 * For Trusted Extensions, we need to check the sensitivity label of the
+	 * connection and job before we return it to the client.
+	 */
+	if ((md->admin <= 0) && (is_system_labeled()) &&
+	    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+	    (!STREQU(md->slabel, rp->secure->slabel)))
+	    continue;
 	
 	if (found) {
 	    GetRequestFiles(found->request, files, sizeof(files));
 	    mputm(md, R_INQUIRE_REQUEST,
 		 MOKMORE,
 		 found->secure->req_id,
-		 found->request->user,
-			/* bgolden 091996, bug 1257405 */
+		 found->request->user, /* bgolden 091996, bug 1257405 */
+		 found->secure->slabel,
 		 found->secure->size,
 		 found->secure->date,
 		 found->request->outcome,
@@ -763,6 +792,7 @@
 	     MOK,
 	     found->secure->req_id,
 	     found->request->user, /* bgolden 091996, bug 1257405 */
+	     found->secure->slabel,
 	     found->secure->size,
 	     found->secure->date,
 	     found->request->outcome,
@@ -772,7 +802,7 @@
 	     files
 	);
     } else
-	mputm(md, R_INQUIRE_REQUEST, MNOINFO, "", "", 0L, 0L, 0, "", "", "",
+	mputm(md, R_INQUIRE_REQUEST, MNOINFO, "", "", "", 0L, 0L, 0, "", "", "",
 	      "");
 
     return;
@@ -829,6 +859,15 @@
 
 		if (*pwheel && !SAME(pwheel, rp->pwheel_name))
 			continue;
+		/*
+		 * For Trusted Extensions, we need to check the sensitivity
+		 * label of the connection and job before we return it to the
+		 * client.
+		 */
+		if ((md->admin <= 0) && (is_system_labeled()) &&
+		    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+		    (!STREQU(md->slabel, rp->secure->slabel)))
+			continue;
 
 		if (found) {
 			GetRequestFiles(found->request, files, sizeof(files));
@@ -837,6 +876,7 @@
 				found->secure->req_id,
 				found->request->user,
 					/* bgolden 091996, bug 1257405 */
+				found->secure->slabel,
 				found->secure->size,
 				found->secure->date,
 				found->request->outcome,
@@ -858,6 +898,7 @@
 			MOK,
 			found->secure->req_id,
 			found->request->user, /* bgolden 091996, bug 1257405 */
+			found->secure->slabel,
 			found->secure->size,
 			found->secure->date,
 			found->request->outcome,
@@ -868,8 +909,8 @@
 			files
 		);
 	} else
-		mputm(md, R_INQUIRE_REQUEST_RANK, MNOINFO, "", "", 0L, 0L, 0,
-			"", "", "", 0, "");
+		mputm(md, R_INQUIRE_REQUEST_RANK, MNOINFO, "", "", "", 0L, 0L,
+			0, "", "", "", 0, "");
 }
 
 static int
@@ -1133,3 +1174,33 @@
 
     return(path);
 }
+
+/*
+ * The client is sending a peer connection to retreive label information
+ * from.  This is used in the event that the client is an intermediary for
+ * the actual requestor in a Trusted environment.
+ */
+void s_pass_peer_connection(char *m, MESG *md)
+{
+	short	status = MTRANSMITERR;
+	char	*dest;
+	struct strrecvfd recv_fd;
+
+	(void) getmessage(m, S_PASS_PEER_CONNECTION);
+	syslog(LOG_DEBUG, "s_pass_peer_connection()");
+
+	memset(&recv_fd, NULL, sizeof (recv_fd));
+	if (ioctl(md->readfd, I_RECVFD, &recv_fd) == 0) {
+		int fd = recv_fd.fd;
+
+		if (get_peer_label(fd, &md->slabel) == 0) {
+			if (md->admin == 1)
+				md->admin = -1; /* turn off query privilege */
+			status = MOK;
+		}
+
+		close(fd);
+	}
+
+	mputm(md, R_PASS_PEER_CONNECTION, status);
+}
--- a/usr/src/cmd/lp/cmd/lpsched/dispatch.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/dispatch.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -82,6 +81,7 @@
 void		s_unmount_tray ( char *, MESG *);
 void		s_paper_changed ( char *, MESG *);
 void		s_paper_allowed ( char *, MESG *);
+void		s_pass_peer_connection ( char * , MESG * );
 	
 /**
  ** dispatch_table[]
--- a/usr/src/cmd/lp/cmd/lpsched/disptab.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/disptab.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -139,6 +138,8 @@
 /* R_PAPER_CHANGED          */  0,			D_BADMSG,
 /* S_PAPER_ALLOWED          */  s_paper_allowed,	0,
 /* R_PAPER_ALLOWED          */  0,			D_BADMSG,
+/* S_PASS_PEER_CONNECTION   */  s_pass_peer_connection,	0,
+/* R_PASS_PEER_CONNECTION   */  0,			D_BADMSG,
 };
 
 static char *			dispatch_names[] = {
@@ -244,6 +245,8 @@
 "R_PAPER_CHANGED",
 "S_PAPER_ALLOWED",
 "R_PAPER_ALLOWED",
+"S_PASS_PEER_CONNECTION",
+"R_PASS_PEER_CONNECTION",
 };
 
 /* see include/msgs.h */
--- a/usr/src/cmd/lp/cmd/lpsched/exec.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/exec.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,6 +28,11 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
+#include <pwd.h>
+#include <zone.h>
+#if defined PS_FAULTED
+#undef  PS_FAULTED
+#endif /* PS_FAULTED */
 #include <dial.h>
 
 #include <stdlib.h>
@@ -38,7 +42,7 @@
 #include "dial.h"
 #include "lpsched.h"
 #include <syslog.h>
-#include <pwd.h>
+#include "tsol/label.h"
 
 #define Done(EC,ERRNO)	done(((EC) << 8),ERRNO)
 
@@ -256,6 +260,7 @@
 }
 
 static char time_buf[50];
+
 /**
  ** exec() - FORK AND EXEC CHILD PROCESS
  **/
@@ -304,6 +309,8 @@
 	char *av[ARG_MAX];
 	char **envp = NULL;
 	int ac = 0;
+	char	*mail_zonename = NULL;
+	char	*slabel = NULL;
 
 	syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
 
@@ -440,7 +447,6 @@
 	for (i = 0; i < OpenMax; i++)
 		if (i != ChildMd->writefd)
 			Close (i);
-
 	setpgrp();
 
 	/* Set a default path */
@@ -717,6 +723,14 @@
 				request->request->user);
 		}
 		/*
+		 * Add the sensitivity label to the environment for
+		 * banner page and header/footer processing
+		 */
+
+		if (is_system_labeled() && request->secure->slabel != NULL)
+			addenv(&envp, "SLABEL", request->secure->slabel);
+
+		/*
 		 * Add the system name to the user name (ala system!user)
 		 * unless it is already there. RFS users may have trouble
 		 * here, sorry!
@@ -1016,9 +1030,8 @@
 					request->request->alert);
 		} else {
 			char *user = strdup(request->secure->user);
-			procuid = Lp_Uid;
-			procgid = Lp_Gid;
 			clean_string(user);
+			slabel = request->secure->slabel;
 
 			if ((request->request->actions & ACT_WRITE) &&
 			    (!request->secure->system ||
@@ -1032,9 +1045,41 @@
 				av[ac++] = arg_string(TRUSTED, "/bin/sh");
 				av[ac++] = arg_string(TRUSTED, "-c");
 				av[ac++] = arg_string(TRUSTED, "%s", argbuf);
-			} else {
+			} else if ((getzoneid() == GLOBAL_ZONEID) &&
+				   is_system_labeled() && (slabel != NULL)) {
+				/*
+				 * If in the global zone and the system is
+				 * labeled, mail is handled via a local
+				 * labeled zone that is the same label as
+				 * the request.
+				 */
+				if ((mail_zonename =
+				    get_labeled_zonename(slabel)) ==
+				    (char *)-1) {
+					/*
+					 * Cannot find labeled zone, just
+					 * return 0.
+					 */
+					return(0);
+				}
+			}
+			if (mail_zonename == NULL) {
+				procuid = Lp_Uid;
+				procgid = Lp_Gid;
 				av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
 				av[ac++] = arg_string(UNTRUSTED, "%s", user);
+			} else {
+				procuid = getuid();
+				procgid = getgid();
+				av[ac++] = arg_string(TRUSTED, "%s",
+				    "/usr/sbin/zlogin");
+				av[ac++] = arg_string(TRUSTED, "%s",
+				    mail_zonename);
+				av[ac++] = arg_string(TRUSTED, "%s",
+				    BINMAIL);
+				av[ac++] = arg_string(UNTRUSTED, "%s",
+				    user);
+				Free(mail_zonename);
 			}
 
 			free(user);
@@ -1070,7 +1115,7 @@
 
 	for (i = 0; av[i] != NULL; i++)
 		syslog(LOG_DEBUG, "exec: av[%d] = %s", i, av[i]);
-	for (i = 0; av[i] != NULL; i++)
+	for (i = 0; envp[i] != NULL; i++)
 		syslog(LOG_DEBUG, "exec: envp[%d] = %s", i, envp[i]);
 
 	execvpe(av[0], av, envp);
--- a/usr/src/cmd/lp/cmd/lpsched/validate.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsched/validate.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,15 +27,23 @@
 /*	  All Rights Reserved  	*/
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.11.1.10	*/
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/* SVr4.0 1.11.1.10	*/
 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
 
 #include "lpsched.h"
 
 #include "validate.h"
 
+#include <syslog.h>
+#include <errno.h>
+#include <deflt.h>
+#include <tsol/label.h>
+#include <auth_list.h>
+
 #define register auto
 
+
 int		pickfilter ( RSTATUS * , CANDIDATE * , FSTATUS * );
 
 unsigned long		chkprinter_result	= 0;
@@ -46,10 +53,14 @@
 char *			o_length	= 0;
 
 static int		wants_nobanner	= 0;
+static int		wants_nolabels	= 0;
 static int		lp_or_root	= 0;
 
 static int		_chkopts ( RSTATUS *, CANDIDATE * , FSTATUS * );
 static void		free_candidate ( CANDIDATE * );
+static int		tsol_check_printer_label_range(char *, const char *);
+static int		tsol_lpauth(char *, char *);
+static int		secpolicy_chkpolicy(char *policyp);
 
 /**
  ** _validate() - FIND A PRINTER TO HANDLE A REQUEST
@@ -79,6 +90,23 @@
 	wants_nobanner = 0;
 	memset (&single, 0, sizeof(single));
 
+	wants_nolabels = 0;
+	/*
+	 * If the system is labeled, the printing of postscript files
+	 * is restricted.  All users can print postscript files if the
+	 * file /etc/default/print contains "PRINT_POSTSCRIPT=1".
+	 * (this is checked by secpolicy_chkpolicy).  Otherwise the
+	 * user must have PRINT_POSTSCRIPT_AUTH to print postscript files.
+	 */
+	if ((is_system_labeled() &&
+	    strcmp(prs->request->input_type, "postscript") == 0) &&
+	    (secpolicy_chkpolicy("PRINT_POSTSCRIPT=") == 0)) {
+		if (tsol_lpauth(PRINT_POSTSCRIPT_AUTH, prs->secure->user)
+		    == 0) {
+			ret = MDENYDEST;
+			goto Return;
+		}
+	}
 	lp_or_root = 0;
 
 	if (STREQU(prs->secure->system, Local_System))
@@ -166,6 +194,8 @@
 					o_length = Strdup(*pl + 7);
 				else if (STREQU(*pl, "nobanner"))
 					wants_nobanner = 1;
+				else if (STREQU(*pl, "nolabels"))
+					wants_nolabels = 1;
 			freelist (list);
 		}
 	}
@@ -296,6 +326,16 @@
 			goto Return;
 		}
 
+		/* Check printer label range */
+		if (is_system_labeled() && prs->secure->slabel != NULL) {
+			if (tsol_check_printer_label_range(
+			    prs->secure->slabel,
+			    pps->printer->name) == 0) {
+				ret = MDENYDEST;
+				goto Return;
+			}
+		}
+
 		/* Does the printer allow the form? */
 		if (pfs && !CHKF(pfs, pps)) {
 			ret = MNOMOUNT;
@@ -563,6 +603,30 @@
 		ret = MOK;
 		goto Return;
 	}
+	/*
+	 * Clean out local printers
+	 * where the request is outside the printer label range.
+	 */
+	{
+		register CANDIDATE	*pcend2;
+
+		if (is_system_labeled()) {
+			for (pcend2 = pc = arena; pc < pcend; pc++) {
+				if (tsol_check_printer_label_range(
+				    prs->secure->slabel,
+				    pps->printer->name) == 1)
+					*pcend2++ = *pc;
+				else
+					free_candidate(pc);
+			}
+		}
+
+		if (pcend2 == arena) {
+			ret = MDENYDEST;
+			goto Return;
+		}
+		pcend = pcend2;
+	}
 
 #if	defined(OTHER_FACTORS)
 	/*
@@ -790,6 +854,7 @@
 	char *			paper = NULL;
 
 	char **			pt;
+	int			nobanner_not_allowed = 0;
 
 
 	/*
@@ -844,11 +909,47 @@
 	if (!pc->printer_types)
 		ret |= chk;
 
+	/*
+	 * If the sytem is labeled, then user who wants 'nolabels' must
+	 * have PRINT_UNLABELED_AUTH authorizations to allow it.
+	 */
+	if (is_system_labeled() && (wants_nolabels == 1)) {
+		if (!tsol_lpauth(PRINT_UNLABELED_AUTH, prs->secure->user)) {
+			/* if not authorized, remove "nolabels" from options */
+			register char		**list;
+			if (prs->request->options &&
+			    (list = dashos(prs->request->options))) {
+				dellist(&list, "nolabels");
+				free(prs->request->options);
+				prs->request->options = sprintlist(list);
+			}
+		}
+	}
+
+
 	if (pc->pps->printer->banner == BAN_ALWAYS) {
-		if ((wants_nobanner == 1) && (lp_or_root != 1)) {
-			/* delete "nobanner" */
-			char **list;
+		/* delete "nobanner" */
+		char **list;
 
+		/*
+		 * If the system is labeled, users must have
+		 * PRINT_NOBANNER_AUTH authorization to print
+		 * without a banner.
+		 */
+		if (is_system_labeled()) {
+			if (wants_nobanner == 1) {
+				if (tsol_lpauth(PRINT_NOBANNER_AUTH,
+					prs->secure->user) == 0) {
+					nobanner_not_allowed = 1;
+				}
+			}
+
+		}
+		else if ((wants_nobanner == 1) && (lp_or_root != 1)) {
+			nobanner_not_allowed = 1;
+		}
+		if (nobanner_not_allowed == 1) {
+			/* Take out 'nobanner' from request options. */
 			if (prs->request->options &&
 			    (list = dashos(prs->request->options))) {
 				dellist(&list, "nobanner");
@@ -897,3 +998,85 @@
 		unload_str (&(pc->output_type));
 	return;
 }
+
+static int
+tsol_check_printer_label_range(char *slabel, const char *printer)
+{
+	int			in_range = 0;
+	int			err = 0;
+	m_range_t		*range;
+	m_label_t	*sl = NULL;
+
+	if (slabel == NULL)
+		return (0);
+
+	if ((err =
+	    (str_to_label(slabel, &sl, USER_CLEAR, L_NO_CORRECTION, &in_range)))
+	    == -1) {
+		/* stobsl error on printer max label */
+		return (0);
+	}
+	if ((range = getdevicerange(printer)) == NULL) {
+		m_label_free(sl);
+		return (0);
+	}
+
+	/* blinrange returns true (1) if in range, false (0) if not */
+	in_range = blinrange(sl, range);
+
+	m_label_free(sl);
+	m_label_free(range->lower_bound);
+	m_label_free(range->upper_bound);
+	free(range);
+
+	return (in_range);
+}
+
+/*
+ * Given a character string with a "username" or "system!username"
+ * this function returns a pointer to "username"
+ */
+static int
+tsol_lpauth(char *auth, char *in_name)
+{
+	char *cp;
+	int res;
+
+	if ((cp = strchr(in_name, '@')) != NULL) {
+		/* user@system */
+		*cp = '\0';
+		res = chkauthattr(auth, in_name);
+		*cp = '@';
+	} else if ((cp = strchr(in_name, '!')) != NULL)
+		/* system!user */
+		res = chkauthattr(auth, cp+1);
+	else
+		/* user */
+		res = chkauthattr(auth, in_name);
+
+	return (res);
+}
+
+#define	POLICY_FILE	"/etc/default/print"
+
+int
+secpolicy_chkpolicy(char *policyp)
+{
+	char *option;
+	int opt_val;
+
+	if (policyp == NULL)
+		return (0);
+	opt_val = 0;
+	if (defopen(POLICY_FILE) == 0) {
+
+		defcntl(DC_SETFLAGS, DC_STD & ~DC_CASE); /* ignore case */
+
+		if ((option = defread(policyp)) != NULL)
+			opt_val = atoi(option);
+	}
+	(void) defopen((char *)NULL);
+	syslog(LOG_DEBUG, "--- Policy %s, opt_val==%d",
+	    policyp ? policyp : "NULL", opt_val);
+	return (opt_val);
+}
--- a/usr/src/cmd/lp/cmd/lpstat/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpstat/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,11 +17,13 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 1989-2002 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/lp/cmd/lpstat/Makefile
@@ -61,7 +62,7 @@
 
 SYSLIBS=	-lcurses
 
-LDLIBS +=	$(LPLIBS) $(SYSLIBS) $(I18N)
+LDLIBS +=	$(LPLIBS) $(SYSLIBS) $(I18N) -z lazyload -lsecdb -z nolazyload
 
 POFILE=		lp_cmd_lpstat.po
 
--- a/usr/src/cmd/lp/cmd/lpstat/lpstat.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpstat/lpstat.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,9 +18,11 @@
  *
  * CDDL HEADER END
  */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	Copyright (c) 2001 by Sun Microsystems, Inc. */
-/*	  All Rights Reserved  	*/
 
 
 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.7	*/
@@ -69,8 +70,8 @@
 void		do_user ( char ** );
 void		done ( int );
 void		parse ( int , char ** );
-void		putoline(char *, char *, long, time_t, int, char *, char *,
-			char *, int);
+void		putoline(char *, char *, char *, long, time_t, int, char *,
+			char *, char *, int);
 void		putpline(char *, int, char *, time_t, char *, char *, char *);
 void		putqline(char *, int, time_t, char *);
 void		putppline ( char * ,  char *);
--- a/usr/src/cmd/lp/cmd/lpstat/output.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpstat/output.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,6 +55,7 @@
 
 	char			*class,
 				*user,
+				*slabel,
 				*reject_reason,
 				*request_id,
 				*printer,
@@ -131,6 +131,7 @@
 				&status,
 				&request_id,
 				&user,
+				&slabel,
 				&size,
 				&date,
 				&state,
@@ -147,8 +148,9 @@
 
 			case MOK:
 			case MOKMORE:
-				putoline(request_id, user, size, date, state,
-					printer, form, character_set, ++rank);
+				putoline(request_id, user, slabel, size, date,
+					state, printer, form, character_set,
+					++rank);
 				break;
 
 			}
@@ -161,6 +163,7 @@
 				&status,
 				&request_id,
 				&user,
+				&slabel,
 				&size,
 				&date,
 				&state,
@@ -178,8 +181,9 @@
 
 			case MOK:
 			case MOKMORE:
-				putoline(request_id, user, size, date, state,
-					printer, form, character_set, rank);
+				putoline(request_id, user, slabel, size, date,
+					state, printer, form, character_set,
+					rank);
 				break;
 
 			}
--- a/usr/src/cmd/lp/cmd/lpstat/request.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpstat/request.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -22,9 +21,8 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved  	*/
 
-
 /*
- * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,6 +34,7 @@
 #include "sys/types.h"
 
 #include "lp.h"
+#include "strings.h"
 #include "msgs.h"
 #include "requests.h"
 
@@ -178,17 +177,24 @@
 	user_name = NULL;
 }
 
+
 /*
  * putoline()
  */
 
 void
-putoline(char *request_id, char *user, long size, time_t clock, int state,
-	char *printer, char *form, char *character_set, int rank)
+putoline(char *request_id, char *user, char *slabel, long size, time_t clock,
+	int state, char *printer, char *form, char *character_set, int rank)
 {
 	int showRank;
+	char user_buf[LOGMAX];
 	char date[SZ_DATE_BUFF];
 
+	if ((slabel != NULL) && (slabel[0] != '\0'))
+		snprintf(user_buf, sizeof (user_buf), "%s:%s", user, slabel);
+	else
+		snprintf(user_buf, sizeof (user_buf), "%s", user);
+
 	/*
 	 * This is the basic time format used in the output. It represents
 	 * all times of the form "Dec 11 11:04" seen in the output.
@@ -215,13 +221,12 @@
 		((showRank) ? IDSIZE - 2 : IDSIZE),
 		request_id,
 		LOGMAX-1,
-		user,
+		user_buf,
 		OSIZE,
 		size,
 		((showRank) ? "" : "  "),
 		date);
 
-
 	if (!(verbosity & (V_LONG|V_BITS))) {
 
 		/*
--- a/usr/src/cmd/lp/cmd/lpsystem.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/cmd/lpsystem.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,14 +19,17 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved  	*/
 
-
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.8	*/
 
@@ -45,6 +47,8 @@
 #include	"systems.h"
 #include	"msgs.h"
 #include	"boolean.h"
+#include	"access.h"
+#include	"tsol/label.h"
 
 #define WHO_AM_I	I_AM_LPSYSTEM
 #include "oam.h"
@@ -283,11 +287,22 @@
 SecurityCheck ()
 #endif
 {
-	if (geteuid () != 0)
-	{
-		(void)	fprintf (stderr,
-			gettext("ERROR:  You must be root.\n"));
-		(void)	exit (1);
+	/* On labeled systems check that user has print admin authorization */
+	if (is_system_labeled()) {
+		if (is_user_admin() == 0) {
+			(void) fprintf(stderr,
+			    gettext(
+			    "You are not authorized to administer printing.\n"\
+			    ));
+			(void) exit (1);
+		}
+	} else {
+		if (geteuid () != 0)
+		{
+			(void)	fprintf (stderr,
+				gettext("ERROR:  You must be root.\n"));
+			(void)	exit (1);
+		}
 	}
 }
 /*==================================================================*/
--- a/usr/src/cmd/lp/include/lp.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/include/lp.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -599,6 +598,14 @@
 
 char *		next_x  ( char * , long * , unsigned int );
 
+/*
+ * Stuff needed for Trusted Extensions
+ */
+
+extern	char	*get_labeled_zonename(char *);
+extern int	get_peer_label(int fd, char **slabel);
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/cmd/lp/include/msgs.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/include/msgs.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -152,10 +151,12 @@
 # define	R_PAPER_CHANGED			99
 # define	S_PAPER_ALLOWED			100
 # define	R_PAPER_ALLOWED			101
+# define	S_PASS_PEER_CONNECTION		102
+# define	R_PASS_PEER_CONNECTION		103
 /*
 **	Last available message
 */
-# define	LAST_MESSAGE			102
+# define	LAST_MESSAGE			104
 
 /*
 **      These are the possible status codes returned by the scheduler
@@ -322,6 +323,7 @@
     MQUE *	mque;			/* backlogged message ptr */
     uid_t	uid;			/* Clients UID */
     gid_t	gid;			/* Clients GID */
+    char *	slabel;			/* Clients SLABEL */
     void	(**on_discon)();	/* Clean up functions */
 } MESG;
 
--- a/usr/src/cmd/lp/include/secure.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/include/secure.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,9 +39,9 @@
  **/
 
 /*
- * There are 7 fields in the secure request file.
+ * There are 8 fields in the secure request file.
  */
-#define	SC_MAX  7
+#define	SC_MAX  8
 # define SC_REQID	0	/* Original request id */
 # define SC_UID		1	/* Originator's user ID */
 # define SC_USER	2	/* Originator's real login name */
@@ -50,6 +49,7 @@
 # define SC_SIZE	4	/* Total size of the request data */
 # define SC_DATE	5	/* Date submitted (in seconds) */
 # define SC_SYSTEM	6	/* Originating system */
+# define SC_SLABEL	7	/* Sensitivity Label */
 
 /**
  ** The internal copy of a request as seen by the rest of the world:
@@ -63,6 +63,7 @@
     char	*system;
     char	*user;
     char	*req_id;
+    char	*slabel;
 }			SECURE;
 
 /**
--- a/usr/src/cmd/lp/lib/access/allowed.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/access/allowed.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,13 @@
 /*	  All Rights Reserved  	*/
 
 
-#ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.7	*/
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
 
 #include "string.h"
@@ -31,6 +36,10 @@
 
 #include "lp.h"
 #include "access.h"
+#include <pwd.h>
+#include <auth_attr.h>
+#include <auth_list.h>
+#include <tsol/label.h>
 
 /**
  ** is_user_admin() - CHECK IF CURRENT USER IS AN ADMINISTRATOR
@@ -45,7 +54,15 @@
 is_user_admin ()
 #endif
 {
-	return (Access(Lp_A, W_OK) == -1? 0 : 1);
+	/* For a labeled system, tsol_check_admin_auth is called
+	 * instead of using Access.
+	 */
+	if (is_system_labeled()) {
+		/* Check that user has print admin authorization */
+		return (tsol_check_admin_auth(getuid()));
+	} else {
+		return (Access(Lp_A, W_OK) == -1? 0 : 1);
+	}
 }
 
 /**
@@ -181,3 +198,22 @@
 
 	return (0);
 }
+
+/*
+ * Check to see if the specified user has the administer the printing
+ * system authorization.
+ */
+int
+tsol_check_admin_auth(uid_t uid)
+{
+	struct passwd *p;
+	char *name;
+
+	p = getpwuid(uid);
+	if (p != NULL && p->pw_name != NULL)
+		name = p->pw_name;
+	else
+		name = "";
+
+	return (chkauthattr(PRINT_ADMIN_AUTH, name));
+}
--- a/usr/src/cmd/lp/lib/lp/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/lp/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -69,6 +70,7 @@
 		syntax.o	\
 		tidbit.o	\
 		tinames.o	\
+		tx.o		\
 		wherelist.o	\
 		which.o
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/lp/lib/lp/tx.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <syslog.h>
+#include <strings.h>
+
+#include <ucred.h>
+#include "tsol/label.h"
+/* lpsched include files */
+#if defined PS_FAULTED
+#undef  PS_FAULTED
+#endif /* PS_FAULTED */
+#include "lp.h"
+
+/*
+ * get_labeled_zonename - gets the the zonename with the same label.
+ *
+ *	Input:
+ *		slabel - USER_CLEAR label to match
+ *
+ *	Output:
+ *		-1 - zonename with that label could not be found
+ *			or no memory for zonename
+ *		 0 - label was GLOBAL_ZONENAME
+ *		 addr - zonename of zone matching USER_CLEAR label
+ *			must be retuened by calling Free(addr)
+ *
+ */
+
+char *
+get_labeled_zonename(char *slabel)
+{
+	m_label_t	*bsl = NULL;
+	int	err = 0;
+	ssize_t	zonename_size = -1;
+	zoneid_t	zid = -1;
+	char *zname = NULL;
+
+	syslog(LOG_DEBUG, "lpsched: get_labeled_zonename %s", slabel);
+	/*
+	 * convert the label to binary.
+	 */
+	if (str_to_label(slabel, &bsl, USER_CLEAR,
+	    L_NO_CORRECTION, &err) == -1) {
+		/* label could not be converted, error */
+		syslog(LOG_WARNING,
+		    "lpsched: %s: label not recognized (error==%d)",
+		    slabel, err);
+		return ((char *)-1);
+	}
+	if ((zid = getzoneidbylabel(bsl)) < 0) {
+		/* no zone with that label, cannot send mail */
+		syslog(LOG_WARNING,
+		    "lpsched: cannot send mail, no zone with %s label",
+		    slabel);
+		m_label_free(bsl);
+		return ((char *)-1);
+	}
+	zname = Malloc(ZONENAME_MAX + 1);
+	if ((zonename_size = getzonenamebyid(zid, zname, ZONENAME_MAX + 1))
+	    == -1) {
+		/* cannot get zone name, cannot send mail */
+		syslog(LOG_WARNING,
+		    "lpsched: cannot send mail, no zone name for %s",
+		    slabel);
+		m_label_free(bsl);
+		Free(zname);
+		return ((char *)-1);
+	} else {
+		m_label_free(bsl);
+		if (strcmp(zname, GLOBAL_ZONENAME) == 0) {
+			Free(zname);
+			zname = NULL;
+		}
+	}
+	return (zname);
+}
+
+int
+get_peer_label(int fd, char **slabel)
+{
+	if (is_system_labeled()) {
+		ucred_t *uc = NULL;
+		m_label_t *sl;
+		char *pslabel = NULL; /* peer's slabel */
+
+		if ((fd < 0) || (slabel == NULL)) {
+			errno = EINVAL;
+			return (-1);
+		}
+
+		if (getpeerucred(fd, &uc) == -1)
+			return (-1);
+
+		sl = ucred_getlabel(uc);
+		if (label_to_str(sl, &pslabel, M_INTERNAL, DEF_NAMES) != 0)
+			syslog(LOG_WARNING, "label_to_str(): %m");
+		ucred_free(uc);
+
+		if (pslabel != NULL) {
+			syslog(LOG_DEBUG, "get_peer_label(%d, %s): becomes %s",
+				fd, (*slabel ? *slabel : "NULL"), pslabel);
+			if (*slabel != NULL)
+				free(*slabel);
+			*slabel = strdup(pslabel);
+		}
+	}
+
+	return (0);
+}
--- a/usr/src/cmd/lp/lib/msgs/mlisten.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/msgs/mlisten.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,9 @@
 # include	<fcntl.h>
 # include	<errno.h>
 #include	<syslog.h>
+#include <user_attr.h>
+#include <secdb.h>
+#include <pwd.h>
 
 # include	"lp.h"
 # include	"msgs.h"
@@ -328,7 +330,21 @@
 		md->type = MD_UNKNOWN;
 		md->uid = recbuf.uid;
 
+		/*
+		 * Determine if a print administrator is contacting lpsched.
+		 * currently, root, lp and users with the "solaris.print.admin"
+		 * privilege are print administrators
+		 */
 		md->admin = (md->uid == 0 || md->uid == Lp_Uid);
+		if (md->admin == 0) { 
+			struct passwd *pw = NULL;
+
+			if ((pw = getpwuid(md->uid)) != NULL)
+				md->admin = chkauthattr("solaris.print.admin",
+							pw->pw_name);
+		}
+	
+		get_peer_label(md->readfd, &md->slabel);
 
 		if (mlistenadd(md, POLLIN) != 0)
 		    return(NULL);
--- a/usr/src/cmd/lp/lib/msgs/msgfmts.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/msgs/msgfmts.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,7 +46,7 @@
     "S",          	/* 11 - S_CANCEL_REQUEST */
     "H",          	/* 12 - R_CANCEL_REQUEST */
     "SSSSS",       	/* 13 - S_INQUIRE_REQUEST */
-    "HSSLLHSSSS",      	/* 14 - R_INQUIRE_REQUEST */
+    "HSSSLLHSSSS",     	/* 14 - R_INQUIRE_REQUEST */
     "S",          	/* 15 - S_LOAD_PRINTER */
     "H",          	/* 16 - R_LOAD_PRINTER */
     "S",          	/* 17 - S_UNLOAD_PRINTER */
@@ -108,7 +107,7 @@
     "SSHH",		/* 72 - S_GET_STATUS */
     "HSHH",		/* 73 - R_GET_STATUS */
     "HSSSSS",		/* 74 - S_INQUIRE_REQUEST_RANK */
-    "HSSLLHSSSHS",	/* 75 - R_INQUIRE_REQUEST_RANK */
+    "HSSSLLHSSSHS",	/* 75 - R_INQUIRE_REQUEST_RANK */
     "SSS",		/* 76 - S_CANCEL */
     "HLS",		/* 77 - R_CANCEL */
     "S",		/* 78 - S_NEW_CHILD */
@@ -136,5 +135,7 @@
     "H",          	/* 99 - R_PAPER_CHANGED */
     "S",          	/* 100 - S_PAPER_ALLOWED */
     "HSS",          	/* 101 - R_PAPER_ALLOWED */
+    "",          	/* 102 - S_PASS_PEER_CONNECTION */
+    "H",          	/* 103 - R_PASS_PEER_CONNECTION */
     0,
 };
--- a/usr/src/cmd/lp/lib/papi/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -45,6 +46,8 @@
 CPPFLAGS +=	-I$(LPINC)
 CPPFLAGS +=	-I$(SRC)/lib
 CPPFLAGS +=	-D_REENTRANT
+CPPFLAGS +=	$(ENVCPPFLAGS1)
+CPPFLAGS +=	$(ENVCPPFLAGS2)
 LDLIBS +=	-lc
 LDLIBS	+=	-L$(SRC)/cmd/lp/lib/msgs -llpmsg
 LDLIBS	+=	-L$(SRC)/cmd/lp/lib/printers -llpprt
--- a/usr/src/cmd/lp/lib/papi/job.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/job.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -783,6 +782,7 @@
 		*request_id = NULL,
 		*charset = NULL,
 		*user = NULL,
+		*slabel = NULL,
 		*file = NULL;
 	time_t date = 0;
 	size_t size = 0;
@@ -801,7 +801,7 @@
 		return (PAPI_SERVICE_UNAVAILABLE);
 
 	if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &request_id,
-			&user, &size, &date, &state, &dest, &form,
+			&user, &slabel, &size, &date, &state, &dest, &form,
 			&charset, &rank, &file) < 0) {
 		detailed_error(svc,
 			gettext("failed to read response from scheduler"));
@@ -814,7 +814,7 @@
 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
 		return (PAPI_TEMPORARY_ERROR);
 
-	job_status_to_attributes(j, request_id, user, size, date, state,
+	job_status_to_attributes(j, request_id, user, slabel, size, date, state,
 				dest, form, charset, rank, file);
 
 	snprintf(req_id, sizeof (req_id), "%d-0", job_id);
--- a/usr/src/cmd/lp/lib/papi/lpsched-jobs.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/lpsched-jobs.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -470,9 +469,9 @@
  * Convert R_REQUEST_* results to the equivalent PAPI attribute representation.
  */
 void
-job_status_to_attributes(job_t *job, char *req_id, char *user, size_t size,
-		time_t date, short state, char *destination, char *form,
-		char *charset, short rank, char *file)
+job_status_to_attributes(job_t *job, char *req_id, char *user, char *slabel,
+		size_t size, time_t date, short state, char *destination,
+		char *form, char *charset, short rank, char *file)
 {
 	char buf[BUFSIZ];
 	char *p;
@@ -517,6 +516,8 @@
 				"lpsched-file", file);
 	addLPString(&job->attributes, PAPI_ATTR_EXCL,
 				"job-name", file);
+	addLPString(&job->attributes, PAPI_ATTR_EXCL,
+				"tsol-sensitivity-label", slabel);
 }
 
 void
--- a/usr/src/cmd/lp/lib/papi/mapfile-vers	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/mapfile-vers	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,14 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -22,7 +23,6 @@
 #
 # CDDL HEADER END
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 # Generic interface definition for usr/src/cmd/lp/lib/papi
 #
@@ -65,6 +65,7 @@
 
 		papiServiceCreate;
 		papiServiceDestroy;
+		papiServiceSetPeer;	# used by to pass peer connection
 		papiServiceSetUserName;
 		papiServiceSetPassword;
 		papiServiceSetEncryption;
--- a/usr/src/cmd/lp/lib/papi/papi_impl.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/papi_impl.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -82,9 +81,9 @@
 extern void lpsched_request_to_job(REQUEST *r, job_t *j);
 
 extern void job_status_to_attributes(job_t *job, char *req_id, char *user,
-				size_t size, time_t date, short state,
-				char *destination, char *form, char *charset,
-				short rank, char *file);
+				char *slabel, size_t size, time_t date,
+				short state, char *destination, char *form,
+				char *charset, short rank, char *file);
 extern papi_status_t addLPString(papi_attribute_t ***list,
 					int flags, char *name, char *value);
 extern papi_status_t addLPStrings(papi_attribute_t ***list,
--- a/usr/src/cmd/lp/lib/papi/printer.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/printer.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -328,14 +327,15 @@
 			*req_id = NULL,
 			*charset = NULL,
 			*owner = NULL,
+			*slabel = NULL,
 			*file = NULL;
 		time_t date = 0;
 		size_t size = 0;
 		short  rank = 0, state = 0;
 
 		if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &req_id,
-				&owner, &size, &date, &state, &dest, &form,
-				&charset, &rank, &file) < 0)
+				&owner, &slabel, &size, &date, &state, &dest,
+				&form, &charset, &rank, &file) < 0)
 			return (PAPI_SERVICE_UNAVAILABLE);
 
 		if ((rc != MOK) && (rc != MOKMORE))
@@ -352,8 +352,8 @@
 		if ((job = calloc(1, sizeof (*job))) == NULL)
 			continue;
 
-		job_status_to_attributes(job, req_id, owner, size, date, state,
-				dest, form, charset, rank, file);
+		job_status_to_attributes(job, req_id, owner, slabel, size,
+				date, state, dest, form, charset, rank, file);
 
 		if ((ptr = strrchr(file, '-')) != NULL) {
 			*++ptr = '0';
--- a/usr/src/cmd/lp/lib/papi/service.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/papi/service.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,6 +35,8 @@
 #include <libintl.h>
 #include <papi_impl.h>
 
+#include <tsol/label.h>
+
 papi_status_t
 papiServiceCreate(papi_service_t *handle, const char *service_name,
 		const char *user_name, const char *password,
@@ -91,6 +92,38 @@
 	}
 }
 
+/*
+ * interface for passing a peer's connection to gather sensitivity labeling
+ * from for Trusted Solaris.
+ */
+papi_status_t
+papiServiceSetPeer(papi_service_t handle, int peerfd)
+{
+	papi_status_t result = PAPI_OK;
+	service_t *svc = handle;
+
+	if (svc == NULL)
+		return (PAPI_BAD_ARGUMENT);
+
+	if (is_system_labeled) {
+		short status;
+
+		if ((snd_msg(svc, S_PASS_PEER_CONNECTION) < 0) ||
+		    (ioctl(svc->md->writefd, I_SENDFD, peerfd) < 0) ||
+		    (rcv_msg(svc, R_PASS_PEER_CONNECTION, &status) < 0))
+			status = MTRANSMITERR;
+
+		if (status != MOK) {
+			detailed_error(svc,
+				gettext("failed to send peer connection: %s"),
+				lpsched_status_string(status));
+			result = lpsched_status_to_papi_status(status);
+		}
+	}
+
+	return (result);
+}
+
 papi_status_t
 papiServiceSetUserName(papi_service_t handle, const char *user_name)
 {
--- a/usr/src/cmd/lp/lib/secure/secure.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/lp/lib/secure/secure.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,7 @@
 
 #include "lp.h"
 #include "secure.h"
+#include <tsol/label.h>
 
 /**
  ** getsecure() - EXTRACT SECURE REQUEST STRUCTURE FROM DISK FILE
@@ -105,6 +105,10 @@
 		case SC_SYSTEM:
 			secbuf.system = Strdup(buf);
 			break;
+
+		case SC_SLABEL:
+			secbuf.slabel = Strdup(buf);
+			break;
 		}
 	}
 	if (errno != 0 || fld != SC_MAX) {
@@ -199,8 +203,31 @@
 		case SC_SYSTEM:
 			(void)fdprintf(fd, "%s\n", secbufp->system);
 			break;
+
+		case SC_SLABEL:
+			if (secbufp->slabel == NULL) {
+				if (is_system_labeled()) {
+					m_label_t *sl;
+
+					sl = m_label_alloc(MAC_LABEL);
+					(void) getplabel(sl);
+					if (label_to_str(sl, &(secbufp->slabel),
+					    M_INTERNAL, DEF_NAMES) != 0) {
+						perror("label_to_str");
+						secbufp->slabel =
+						    strdup("bad_label");
+					}
+					m_label_free(sl);
+					(void) fdprintf(fd, "%s\n",
+					    secbufp->slabel);
+				} else {
+					(void) fdprintf(fd, "none\n");
+				}
+			} else {
+				(void) fdprintf(fd, "%s\n", secbufp->slabel);
+			}
+			break;
 		}
-
 	close(fd);
 
 	return (0);
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c	Fri Mar 24 12:29:20 2006 -0800
@@ -93,6 +93,7 @@
 #include "sobj.h"
 #include "sysevent.h"
 #include "rctl.h"
+#include "tsol.h"
 #include "typegraph.h"
 #include "ldi.h"
 #include "vfs.h"
@@ -3388,7 +3389,7 @@
 	/* from net.c */
 	{ "mi", ":[-p] [-d | -m]", "filter and display MI object or payload",
 		mi },
-	{ "netstat", "[-av] [-f inet | inet6 | unix] [-P tcp | udp]",
+	{ "netstat", "[-arv] [-f inet | inet6 | unix] [-P tcp | udp]",
 		"show network statistics", netstat },
 	{ "sonode", "?[-f inet | inet6 | unix | #] "
 		"[-t stream | dgram | raw | #] [-p #]",
@@ -3763,6 +3764,12 @@
 	{ "tsd", "walk list of thread-specific data",
 		tsd_walk_init, tsd_walk_step, tsd_walk_fini },
 
+	/* from tsol.c */
+	{ "tnrh", "walk remote host cache structures",
+	    tnrh_walk_init, tnrh_walk_step, tnrh_walk_fini },
+	{ "tnrhtp", "walk remote host template structures",
+	    tnrhtp_walk_init, tnrhtp_walk_step, tnrhtp_walk_fini },
+
 	/*
 	 * typegraph does not work under kmdb, as it requires too much memory
 	 * for its internal data structures.
--- a/usr/src/cmd/mdb/common/modules/genunix/net.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/mdb/common/modules/genunix/net.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -57,8 +56,14 @@
 #define	ADDR_V6_WIDTH	23
 #define	ADDR_V4_WIDTH	15
 
-#define	NETSTAT_ALL	0x1
-#define	NETSTAT_VERBOSE	0x2
+#define	NETSTAT_ALL	0x01
+#define	NETSTAT_VERBOSE	0x02
+#define	NETSTAT_ROUTE	0x04
+#define	NETSTAT_V4	0x08
+#define	NETSTAT_V6	0x10
+#define	NETSTAT_UNIX	0x20
+
+#define	NETSTAT_FIRST	0x80000000u
 
 /*
  * Print an IPv4 address and port number in a compact and easy to read format
@@ -790,6 +795,305 @@
 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
 }
 
+static void
+get_ifname(const ire_t *ire, char *intf)
+{
+	ill_t ill;
+
+	*intf = '\0';
+	if (ire->ire_type == IRE_CACHE) {
+		queue_t stq;
+
+		if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) ==
+		    -1)
+			return;
+		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1)
+			return;
+		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
+		    (uintptr_t)ill.ill_name);
+	} else if (ire->ire_ipif != NULL) {
+		ipif_t ipif;
+		char *cp;
+
+		if (mdb_vread(&ipif, sizeof (ipif),
+		    (uintptr_t)ire->ire_ipif) == -1)
+			return;
+		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) ==
+		    -1)
+			return;
+		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
+		    (uintptr_t)ill.ill_name);
+		if (ipif.ipif_id != 0) {
+			cp = intf + strlen(intf);
+			(void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf),
+			    ":%u", ipif.ipif_id);
+		}
+	}
+}
+
+static void
+get_v4flags(const ire_t *ire, char *flags)
+{
+	(void) strcpy(flags, "U");
+	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
+	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
+		(void) strcat(flags, "G");
+	if (ire->ire_mask == IP_HOST_MASK)
+		(void) strcat(flags, "H");
+	if (ire->ire_type == IRE_HOST_REDIRECT)
+		(void) strcat(flags, "D");
+	if (ire->ire_type == IRE_CACHE)
+		(void) strcat(flags, "A");
+	if (ire->ire_type == IRE_BROADCAST)
+		(void) strcat(flags, "B");
+	if (ire->ire_type == IRE_LOCAL)
+		(void) strcat(flags, "L");
+	if (ire->ire_flags & RTF_MULTIRT)
+		(void) strcat(flags, "M");
+	if (ire->ire_flags & RTF_SETSRC)
+		(void) strcat(flags, "S");
+}
+
+static int
+ip_mask_to_plen(ipaddr_t mask)
+{
+	int i;
+
+	if (mask == 0)
+		return (0);
+	for (i = 32; i > 0; i--, mask >>= 1)
+		if (mask & 1)
+			break;
+	return (i);
+}
+
+static int
+netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
+{
+	const ire_t *ire = walk_data;
+	uint_t *opts = cb_data;
+	ipaddr_t gate;
+	char flags[10], intf[LIFNAMSIZ + 1];
+
+	if (ire->ire_ipversion != IPV4_VERSION || ire->ire_in_src_addr != 0 ||
+	    ire->ire_in_ill != NULL)
+		return (WALK_NEXT);
+
+	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
+	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
+		return (WALK_NEXT);
+
+	if (*opts & NETSTAT_FIRST) {
+		*opts &= ~NETSTAT_FIRST;
+		mdb_printf("%<u>%s Table: IPv4%</u>\n",
+		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
+		if (*opts & NETSTAT_VERBOSE) {
+			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
+			    " Ref Flg Out   In/Fwd%</u>\n",
+			    "Address", ADDR_V4_WIDTH, "Destination",
+			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
+		} else {
+			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
+			    "Interface%</u>\n",
+			    "Address", ADDR_V4_WIDTH, "Destination",
+			    ADDR_V4_WIDTH, "Gateway");
+		}
+	}
+
+	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
+	    ire->ire_src_addr : ire->ire_gateway_addr;
+
+	get_v4flags(ire, flags);
+
+	get_ifname(ire, intf);
+
+	if (*opts & NETSTAT_VERBOSE) {
+		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
+		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
+		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
+		    ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
+		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
+		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
+	} else {
+		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
+		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
+		    ire->ire_refcnt,
+		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
+	}
+
+	return (WALK_NEXT);
+}
+
+static int
+netstat_irev4src_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
+{
+	const ire_t *ire = walk_data;
+	uint_t *opts = cb_data;
+	ipaddr_t gate;
+	char flags[10], intf[LIFNAMSIZ + 1], srcif[LIFNAMSIZ + 1];
+	char dest[ADDR_V4_WIDTH + 3 + 1];
+	ill_t ill;
+
+	if (ire->ire_ipversion != IPV4_VERSION ||
+	    (ire->ire_in_src_addr == 0 && ire->ire_in_ill == NULL))
+		return (WALK_NEXT);
+
+	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
+	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
+		return (WALK_NEXT);
+
+	if (*opts & NETSTAT_FIRST) {
+		*opts &= ~NETSTAT_FIRST;
+		mdb_printf("\n%<u>%s Table: IPv4 Source-Specific%</u>\n",
+		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
+		if (*opts & NETSTAT_VERBOSE) {
+			mdb_printf("%<u>%-?s %-*s In If       %-*s %-*s "
+			    "Out If      Mxfrg Rtt   Ref Flg Out   In/Fwd"
+			    "%</u>\n",
+			    "Address", ADDR_V4_WIDTH+3, "Destination",
+			    ADDR_V4_WIDTH, "Source", ADDR_V4_WIDTH, "Gateway");
+		} else {
+			mdb_printf("%<u>%-?s %-*s In If    %-*s %-*s Flags "
+			    "Ref  Use   Out If%</u>\n",
+			    "Address", ADDR_V4_WIDTH+3, "Destination",
+			    ADDR_V4_WIDTH, "Source", ADDR_V4_WIDTH, "Gateway");
+		}
+	}
+
+	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
+	    ire->ire_src_addr : ire->ire_gateway_addr;
+
+	get_v4flags(ire, flags);
+
+	get_ifname(ire, intf);
+
+	srcif[0] = '\0';
+	if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ire->ire_in_ill) != -1)
+		(void) mdb_readstr(srcif, MIN(LIFNAMSIZ, ill.ill_name_length),
+		    (uintptr_t)ill.ill_name);
+
+	if (ire->ire_in_src_addr != 0 && ire->ire_addr == 0 &&
+	    ire->ire_mask == 0)
+		strcpy(dest, "  --");
+	else
+		mdb_snprintf(dest, sizeof (dest), "%I/%d", ire->ire_addr,
+		    ip_mask_to_plen(ire->ire_mask));
+
+	if (*opts & NETSTAT_VERBOSE) {
+		mdb_printf("%?p %-*s %-11s %-*I %-*I %-11s %5u%c %4u %3u %-3s "
+		    "%5u %u\n", kaddr, ADDR_V4_WIDTH+3, dest, srcif,
+		    ADDR_V4_WIDTH, ire->ire_in_src_addr, ADDR_V4_WIDTH, gate,
+		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
+		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
+		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
+	} else {
+		mdb_printf("%?p %-*s %-8s %-*I %-*I %-5s %4u %5u %s\n", kaddr,
+		    ADDR_V4_WIDTH+3, dest, srcif, ADDR_V4_WIDTH,
+		    ire->ire_in_src_addr, ADDR_V4_WIDTH, gate, flags,
+		    ire->ire_refcnt,
+		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+ip_mask_to_plen_v6(const in6_addr_t *v6mask)
+{
+	int plen;
+	int i;
+	uint32_t val;
+
+	for (i = 3; i >= 0; i--)
+		if (v6mask->s6_addr32[i] != 0)
+			break;
+	if (i < 0)
+		return (0);
+	plen = 32 + 32 * i;
+	val = v6mask->s6_addr32[i];
+	while (!(val & 1)) {
+		val >>= 1;
+		plen--;
+	}
+
+	return (plen);
+}
+
+static int
+netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
+{
+	const ire_t *ire = walk_data;
+	uint_t *opts = cb_data;
+	const in6_addr_t *gatep;
+	char deststr[ADDR_V6_WIDTH + 5];
+	char flags[10], intf[LIFNAMSIZ + 1];
+	int masklen;
+
+	if (ire->ire_ipversion != IPV6_VERSION)
+		return (WALK_NEXT);
+
+	if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE)
+		return (WALK_NEXT);
+
+	if (*opts & NETSTAT_FIRST) {
+		*opts &= ~NETSTAT_FIRST;
+		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
+		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
+		if (*opts & NETSTAT_VERBOSE) {
+			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
+			    "Flags Out    In/Fwd%</u>\n",
+			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
+			    ADDR_V6_WIDTH, "Gateway");
+		} else {
+			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
+			    "%</u>\n",
+			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
+			    ADDR_V6_WIDTH, "Gateway");
+		}
+	}
+
+	gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ?
+	    &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6;
+
+	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
+	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
+	    &ire->ire_addr_v6, masklen);
+
+	(void) strcpy(flags, "U");
+	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
+	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
+		(void) strcat(flags, "G");
+	if (masklen == IPV6_ABITS)
+		(void) strcat(flags, "H");
+	if (ire->ire_type == IRE_HOST_REDIRECT)
+		(void) strcat(flags, "D");
+	if (ire->ire_type == IRE_CACHE)
+		(void) strcat(flags, "A");
+	if (ire->ire_type == IRE_LOCAL)
+		(void) strcat(flags, "L");
+	if (ire->ire_flags & RTF_MULTIRT)
+		(void) strcat(flags, "M");
+	if (ire->ire_flags & RTF_SETSRC)
+		(void) strcat(flags, "S");
+
+	get_ifname(ire, intf);
+
+	if (*opts & NETSTAT_VERBOSE) {
+		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
+		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
+		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
+		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt,
+		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
+	} else {
+		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
+		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
+		    ire->ire_refcnt,
+		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
+	}
+
+	return (WALK_NEXT);
+}
+
 /*ARGSUSED*/
 int
 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
@@ -800,23 +1104,55 @@
 
 	if (mdb_getopts(argc, argv,
 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
-	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
 	    'f', MDB_OPT_STR, &optf,
 	    'P', MDB_OPT_STR, &optP,
+	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
+	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
 	    NULL) != argc)
 		return (DCMD_USAGE);
 
 	if (optP != NULL) {
 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0))
 			return (DCMD_USAGE);
-
+		if (opts & NETSTAT_ROUTE)
+			return (DCMD_USAGE);
 	}
 
-	if (optf != NULL) {
-		if ((strcmp("inet", optf) != 0) &&
-		    (strcmp("inet6", optf) != 0) &&
-		    (strcmp("unix", optf) != 0))
+	if (optf == NULL)
+		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
+	else if (strcmp("inet", optf) == 0)
+		opts |= NETSTAT_V4;
+	else if (strcmp("inet6", optf) == 0)
+		opts |= NETSTAT_V6;
+	else if (strcmp("unix", optf) == 0)
+		opts |= NETSTAT_UNIX;
+	else
+		return (DCMD_USAGE);
+
+	if (opts & NETSTAT_ROUTE) {
+		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
 			return (DCMD_USAGE);
+		if (opts & NETSTAT_V4) {
+			opts |= NETSTAT_FIRST;
+			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
+				mdb_warn("failed to walk ip`ire");
+				return (DCMD_ERR);
+			}
+			opts |= NETSTAT_FIRST;
+			if (mdb_walk("ip`ire", netstat_irev4src_cb,
+			    &opts) == -1) {
+				mdb_warn("failed to walk ip`ire");
+				return (DCMD_ERR);
+			}
+		}
+		if (opts & NETSTAT_V6) {
+			opts |= NETSTAT_FIRST;
+			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
+				mdb_warn("failed to walk ip`ire");
+				return (DCMD_ERR);
+			}
+		}
+		return (DCMD_OK);
 	}
 
 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/genunix/tsol.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,231 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/tsol/tndb.h>
+#include <sys/modhash_impl.h>
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ks.h>
+
+#include "tsol.h"
+#include "modhash.h"
+
+/* ****************** tnrh ****************** */
+
+typedef struct tnrh_walk_s {
+	tnrhc_hash_t **hptr;
+	int idx;
+	tnrhc_hash_t *tnrhc_table[TSOL_MASK_TABLE_SIZE];
+	tnrhc_hash_t *tnrhc_table_v6[TSOL_MASK_TABLE_SIZE_V6];
+} tnrh_walk_t;
+
+/*
+ * Free the mdb storage pointed to by the given per-prefix table.
+ */
+static void
+free_table(tnrhc_hash_t **table, int ntable)
+{
+	while (--ntable >= 0) {
+		if (*table != NULL)
+			mdb_free(*table, TNRHC_SIZE * sizeof (**table));
+		table++;
+	}
+}
+
+/*
+ * Read in a list of per-prefix-length hash tables.  Allocate storage for the
+ * hashes that are present.  On successful return, the table will contain
+ * pointers to mdb-resident storage, not kernel addresses.  On failure, the
+ * contents will not point to any mdb storage.
+ */
+static int
+read_table(const char *symname, tnrhc_hash_t **table, int ntable)
+{
+	GElf_Sym tnrhc_hash;
+	tnrhc_hash_t **hp;
+	uintptr_t addr;
+
+	if (mdb_lookup_by_name(symname, &tnrhc_hash) == -1) {
+		mdb_warn("failed to read %s", symname);
+		return (-1);
+	}
+	if (mdb_vread(table, ntable * sizeof (*table),
+	    tnrhc_hash.st_value) == -1) {
+		mdb_warn("can't read %s at %p", symname, tnrhc_hash.st_value);
+		return (-1);
+	}
+	for (hp = table; hp < table + ntable; hp++) {
+		if ((addr = (uintptr_t)*hp) != 0) {
+			*hp = mdb_alloc(TNRHC_SIZE * sizeof (**hp), UM_SLEEP);
+			if (mdb_vread(*hp, TNRHC_SIZE * sizeof (**hp),
+			    addr) == -1) {
+				mdb_warn("can't read %s[%d] at %p", symname,
+				    hp - table, addr);
+				free_table(table, (hp - table) + 1);
+				return (-1);
+			}
+		}
+	}
+	return (0);
+}
+
+int
+tnrh_walk_init(mdb_walk_state_t *wsp)
+{
+	tnrh_walk_t *twp;
+
+	twp = mdb_alloc(sizeof (*twp), UM_SLEEP);
+
+	if (read_table("tnrhc_table", twp->tnrhc_table,
+	    TSOL_MASK_TABLE_SIZE) == -1) {
+		mdb_free(twp, sizeof (*twp));
+		return (WALK_ERR);
+	}
+	if (read_table("tnrhc_table_v6", twp->tnrhc_table_v6,
+	    TSOL_MASK_TABLE_SIZE_V6) == -1) {
+		free_table(twp->tnrhc_table, TSOL_MASK_TABLE_SIZE);
+		mdb_free(twp, sizeof (*twp));
+		return (WALK_ERR);
+	}
+
+	twp->hptr = twp->tnrhc_table;
+	twp->idx = 0;
+	wsp->walk_addr = 0;
+	wsp->walk_data = twp;
+
+	return (WALK_NEXT);
+}
+
+int
+tnrh_walk_step(mdb_walk_state_t *wsp)
+{
+	tnrh_walk_t *twp = wsp->walk_data;
+	tsol_tnrhc_t tnrhc;
+	int status;
+
+	while (wsp->walk_addr == NULL) {
+		if (*twp->hptr == NULL || twp->idx >= TNRHC_SIZE) {
+			twp->hptr++;
+			if (twp->hptr == twp->tnrhc_table +
+			    TSOL_MASK_TABLE_SIZE)
+				twp->hptr = twp->tnrhc_table_v6;
+			else if (twp->hptr == twp->tnrhc_table_v6 +
+			    TSOL_MASK_TABLE_SIZE_V6)
+				return (WALK_DONE);
+			twp->idx = 0;
+		} else {
+			wsp->walk_addr = (uintptr_t)(*twp->hptr)[twp->idx++].
+			    tnrh_list;
+		}
+	}
+
+	if (mdb_vread(&tnrhc, sizeof (tnrhc), wsp->walk_addr) == -1) {
+		mdb_warn("can't read tsol_tnrhc_t at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, &tnrhc,
+	    wsp->walk_cbdata);
+
+	wsp->walk_addr = (uintptr_t)tnrhc.rhc_next;
+	return (status);
+}
+
+void
+tnrh_walk_fini(mdb_walk_state_t *wsp)
+{
+	tnrh_walk_t *twp = wsp->walk_data;
+
+	free_table(twp->tnrhc_table, TSOL_MASK_TABLE_SIZE);
+	free_table(twp->tnrhc_table_v6, TSOL_MASK_TABLE_SIZE_V6);
+	mdb_free(twp, sizeof (*twp));
+}
+
+/* ****************** tnrhtp ****************** */
+
+typedef struct tnrhtp_walk_data_s {
+	int (*old_callback)(uintptr_t, const void *, void *);
+	void *old_cbdata;
+} tnrhtp_walk_data_t;
+
+/* ARGSUSED */
+static int
+tnrhtp_walk_callback(uintptr_t addr, const void *data, void *private)
+{
+	const struct mod_hash_entry *mhe = data;
+	tnrhtp_walk_data_t *twd = private;
+	tsol_tpc_t tpc;
+
+	if (mdb_vread(&tpc, sizeof (tpc), (uintptr_t)mhe->mhe_val) == -1) {
+		mdb_warn("failed to read tsol_tpc_t at %p", mhe->mhe_val);
+		return (WALK_ERR);
+	} else {
+		return (twd->old_callback((uintptr_t)mhe->mhe_val, &tpc,
+		    twd->old_cbdata));
+	}
+}
+
+int
+tnrhtp_walk_init(mdb_walk_state_t *wsp)
+{
+	mod_hash_t *tpc_name_hash;
+
+	if (mdb_readvar(&tpc_name_hash, "tpc_name_hash") == -1) {
+		mdb_warn("failed to read tpc_name_hash");
+		return (WALK_ERR);
+	}
+
+	wsp->walk_addr = (uintptr_t)tpc_name_hash;
+
+	return (modent_walk_init(wsp));
+}
+
+int
+tnrhtp_walk_step(mdb_walk_state_t *wsp)
+{
+	tnrhtp_walk_data_t twd;
+	int retv;
+
+	twd.old_callback = wsp->walk_callback;
+	twd.old_cbdata = wsp->walk_cbdata;
+	wsp->walk_callback = tnrhtp_walk_callback;
+	wsp->walk_cbdata = &twd;
+
+	retv = modent_walk_step(wsp);
+
+	wsp->walk_callback = twd.old_callback;
+	wsp->walk_cbdata = twd.old_cbdata;
+
+	return (retv);
+}
+
+void
+tnrhtp_walk_fini(mdb_walk_state_t *wsp)
+{
+	modent_walk_fini(wsp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/genunix/tsol.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_TSOL_H
+#define	_TSOL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+extern int tnrh_walk_init(mdb_walk_state_t *);
+extern int tnrh_walk_step(mdb_walk_state_t *);
+extern void tnrh_walk_fini(mdb_walk_state_t *);
+
+extern int tnrhtp_walk_init(mdb_walk_state_t *);
+extern int tnrhtp_walk_step(mdb_walk_state_t *);
+extern void tnrhtp_walk_fini(mdb_walk_state_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _TSOL_H */
--- a/usr/src/cmd/mdb/intel/amd64/genunix/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/mdb/intel/amd64/genunix/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -58,6 +59,7 @@
 	sysevent.c \
 	thread.c \
 	tsd.c \
+	tsol.c \
 	vfs.c \
 	zone.c
 
--- a/usr/src/cmd/mdb/intel/ia32/genunix/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/mdb/intel/ia32/genunix/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -58,6 +59,7 @@
 	sysevent.c \
 	thread.c \
 	tsd.c \
+	tsol.c \
 	vfs.c \
 	zone.c
 
--- a/usr/src/cmd/mdb/sparc/v9/genunix/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/mdb/sparc/v9/genunix/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -58,6 +59,7 @@
 	sysevent.c \
 	thread.c \
 	tsd.c \
+	tsol.c \
 	vfs.c \
 	zone.c
 
--- a/usr/src/cmd/netfiles/nsswitch.dns	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/netfiles/nsswitch.dns	Fri Mar 24 12:29:20 2006 -0800
@@ -1,9 +1,9 @@
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -64,3 +64,6 @@
 auth_attr:  files
 prof_attr:  files
 project:    files
+
+tnrhtp:     files
+tnrhdb:     files
--- a/usr/src/cmd/netfiles/nsswitch.files	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/netfiles/nsswitch.files	Fri Mar 24 12:29:20 2006 -0800
@@ -1,9 +1,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,7 +17,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -54,3 +53,6 @@
 auth_attr:  files
 prof_attr:  files
 project:    files
+
+tnrhtp:     files
+tnrhdb:     files
--- a/usr/src/cmd/netfiles/nsswitch.ldap	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/netfiles/nsswitch.ldap	Fri Mar 24 12:29:20 2006 -0800
@@ -1,9 +1,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,7 +17,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -62,9 +61,12 @@
 # for efficient getservbyname() avoid ldap
 services:   files ldap
 
-printers:	user files ldap
+printers:   user files ldap
 
-auth_attr: files ldap
-prof_attr: files ldap
+auth_attr:  files ldap
+prof_attr:  files ldap
 
 project:    files ldap
+
+tnrhtp:     files ldap
+tnrhdb:     files ldap
--- a/usr/src/cmd/nscd/server.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/nscd/server.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -70,6 +69,10 @@
 #include <ucred.h>
 #include <priv.h>
 #include <libscf.h>
+#include <tsol/label.h>
+#include <zone.h>
+
+#define	TSOL_NAME_SERVICE_DOOR	"/var/tsol/doors/name_service_door"
 
 extern int 	optind;
 extern int 	opterr;
@@ -473,6 +476,18 @@
 	struct sigaction action;
 
 	/*
+	 * The admin model for TX is that labeled zones are managed
+	 * in global zone where most trusted configuration database
+	 * resides.
+	 */
+	if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) {
+		(void) fprintf(stderr,
+		    "With Trusted Extensions nscd runs only in " \
+		    "the global zone.\n");
+		exit(1);
+	}
+
+	/*
 	 *  Special case non-root user  here - he can just print stats
 	 */
 
@@ -802,12 +817,28 @@
 
 	/* bind to file system */
 
-	if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
+	if (is_system_labeled()) {
+		if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
+			int newfd;
+			if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
+				logit("Cannot create %s:%s\n",
+				    TSOL_NAME_SERVICE_DOOR, strerror(errno));
+				exit(1);
+			}
+			(void) close(newfd);
+		}
+		if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
+			if (errno != EEXIST) {
+				logit("Cannot symlink %s:%s\n",
+				    NAME_SERVICE_DOOR, strerror(errno));
+				exit(1);
+			}
+		}
+	} else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
 		int newfd;
 		if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
-			logit("Cannot create %s:%s\n",
-				NAME_SERVICE_DOOR,
-				strerror(errno));
+			logit("Cannot create %s:%s\n", NAME_SERVICE_DOOR,
+			    strerror(errno));
 			exit(1);
 		}
 		(void) close(newfd);
--- a/usr/src/cmd/nscd/svc-nscd	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/nscd/svc-nscd	Fri Mar 24 12:29:20 2006 -0800
@@ -1,11 +1,11 @@
 #!/sbin/sh
 #
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,14 +20,41 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 
 . /lib/svc/share/smf_include.sh
 
+# Trusted Extensions non-global zones need special handling
+
+if (smf_is_system_labeled); then
+	if (smf_is_nonglobalzone); then
+
+        	# If needed create a door to the global zone daemon.
+        	if [ ! -L /var/run/name_service_door ]; then
+                	ln -s /var/tsol/doors/name_service_door /var/run || \
+                    	exit $SMF_EXIT_ERR_FATAL
+        	fi
+
+        	# If current service duration is not "transient", create
+        	# a dummy background process to preserve contract lifetime.
+        	duration=""
+        	if /bin/svcprop -q -c -p startd/duration $SMF_FMRI ; then
+                	duration=`/bin/svcprop -c -p startd/duration $SMF_FMRI`
+        	fi
+        	if [ "$duration" != "transient" ]; then
+                	( while true ; do sleep 3600 ; done ) &
+        	fi
+
+        	# The real daemon is not started in non-global zones,
+		# so exit now.
+        	exit $SMF_EXIT_OK
+	fi
+
+fi
+
 if [ -f /etc/nscd.conf -a -f /usr/sbin/nscd ]; then
 	secure=""
 
--- a/usr/src/cmd/praudit/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/praudit/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -42,7 +43,9 @@
 CPPFLAGS += -D_PRAUDIT -I$(SRC)/lib/libbsm/common
 CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
 
-LDLIBS += -lbsm -lnsl -lpam
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += -lbsm -lnsl -lpam $(LAZYLIBS)
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/praudit/token.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/praudit/token.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -65,9 +64,8 @@
 #include <bsm/audit_record.h>
 #include <bsm/libbsm.h>
 
-#ifdef	TSOL
 #include <tsol/label.h>
-#endif	/* TSOL */
+#include <sys/tsol/label_macro.h>
 
 #include "praudit.h"
 #include "toktable.h"
@@ -2154,10 +2152,8 @@
 int
 slabel_token(pr_context_t *context)
 {
-#ifdef	TSOL
 	bslabel_t label;
 	int	returnstat;
-	int	s;
 	char	strbuf[2048];
 	char	*sp = strbuf;
 	uval_t	uval;
@@ -2166,9 +2162,9 @@
 	    sizeof (label))) == 0) {
 		uval.uvaltype = PRA_STRING;
 		if (!(context->format & PRF_RAWM)) {
-			/* print in ASCII form using bltos */
-			s = bsltos(&label, &sp, sizeof (strbuf), 0);
-			if (s > 0) {
+			/* print in ASCII form */
+			if (label_to_str(&label, &sp, M_LABEL,
+			    DEF_NAMES) == 0) {
 				uval.string_val = sp;
 				returnstat = pa_print(context, &uval, 1);
 			} else /* cannot convert to string */
@@ -2185,9 +2181,6 @@
 		}
 	}
 	return (returnstat);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
 }
 
 /*
@@ -2280,108 +2273,3 @@
 	/* privilege: */
 	return (pa_adr_string(context, returnstat, 1));
 }
-
-/*
- * -----------------------------------------------------------------------
- * ilabel_token() 	: Process information label token and display contents
- * return codes 	: -1 - error
- *			:  0 - successful
- * NOTE: At the time of call, the ilabel token id has been retrieved
- *
- * Format of information label token:
- *	label token id		adr_char
- *	label			adr_opaque, sizeof (bilabel_t) bytes
- * -----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-int
-ilabel_token(pr_context_t *context)
-{
-#ifdef	TSOL
-	bilabel_t label;
-	int	returnstat;
-	int	s;
-	char	strbuf[2048];
-	char	*sp = strbuf;
-	uval_t	uval;
-
-	if ((returnstat = pr_adr_char(context, (char *)&label,
-	    sizeof (label))) == 0) {
-		uval.uvaltype = PRA_STRING;
-		if (!(context->format & PRF_RAWM)) {
-			/* print in ASCII form using bltos */
-			s = biltos(&label, &sp, sizeof (strbuf), 0);
-			if (s > 0) {
-				uval.string_val = sp;
-				returnstat = pa_print(context, &uval, 1);
-			} else /* cannot convert to string */
-				returnstat = 1;
-		}
-		/* print in hexadecimal form */
-		if ((context->format & PRF_RAWM) || (returnstat == 1)) {
-			uval.string_val = hexconvert((char *)&label,
-			    sizeof (bilabel_t), sizeof (bilabel_t));
-			if (uval.string_val) {
-				returnstat = pa_print(context, &uval, 1);
-				free(uval.string_val);
-			}
-		}
-	}
-	return (returnstat);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
-}
-
-/*
- * -----------------------------------------------------------------------
- * clearance_token()	: Process clearance token and display contents
- * return codes 	: -1 - error
- *			:  0 - successful
- * NOTE: At the time of call, the clearance token id has been retrieved
- *
- * Format of clearance token:
- *	clearance token id	adr_char
- *	clearance		adr_char, sizeof (bclear_t) bytes
- * -----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-int
-clearance_token(pr_context_t *context)
-{
-#ifdef	TSOL
-	bclear_t clearance;
-	int	returnstat;
-	int	s;
-	char	strbuf[2048];
-	char	*sp = strbuf;
-	uval_t	uval;
-
-	if ((returnstat = pr_adr_char(context, (char *)&clearance,
-	    sizeof (clearance))) == 0) {
-		uval.uvaltype = PRA_STRING;
-		if (!(context->format & PRF_RAWM)) {
-			/* print in ASCII form using bltos */
-			s = bcleartos(&clearance, &sp, sizeof (strbuf),
-			    SHORT_WORDS);
-			if (s > 0) {
-				uval.string_val = sp;
-				returnstat = pa_print(context, &uval, 1);
-			} else /* cannot convert to string */
-				returnstat = 1;
-		}
-		/* print in hexadecimal form */
-		if ((context->format & PRF_RAWM) || (returnstat == 1)) {
-			uval.string_val = hexconvert((char *)&clearance,
-			    sizeof (bclear_t), sizeof (bclear_t));
-			if (uval.string_val) {
-				returnstat = pa_print(context, &uval, 1);
-				free(uval.string_val);
-			}
-		}
-	}
-	return (returnstat);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
-}
--- a/usr/src/cmd/praudit/toktable.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/praudit/toktable.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -116,14 +115,9 @@
 	table_init(AUT_ACL, "acl", acl_token, T_ENCLOSED);
 	table_init(AUT_ATTR, "attribute", attribute_token, T_ENCLOSED);
 	table_init(AUT_IPC_PERM, "IPC_perm", s5_IPC_perm_token, T_ENCLOSED);
-	table_initx(AUT_LABEL, "cmw label", "cmw_label",
-	    NOFUNC, T_UNKNOWN);
 	table_init(AUT_GROUPS, "group", group_token, T_ELEMENT);
-	table_initx(AUT_ILABEL, "information label", "information_label",
-	    ilabel_token, T_ELEMENT);
-	table_initx(AUT_SLABEL, "sensitivity label", "sensitivity_label",
+	table_initx(AUT_LABEL, "sensitivity label", "sensitivity_label",
 	    slabel_token, T_ELEMENT);
-	table_init(AUT_CLEAR, "clearance", clearance_token, T_ELEMENT);
 	table_init(AUT_PRIV, "privilege", privilege_token, T_EXTENDED);
 	table_initx(AUT_UPRIV, "use of privilege", "use_of_privilege",
 	    useofpriv_token, T_EXTENDED);
--- a/usr/src/cmd/praudit/toktable.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/praudit/toktable.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -200,9 +199,7 @@
 extern int	attribute_token();
 extern int	s5_IPC_perm_token();
 extern int	group_token();
-extern int 	ilabel_token();
 extern int	slabel_token();
-extern int	clearance_token();
 extern int	privilege_token();
 extern int	useofpriv_token();
 extern int	liaison_token();
--- a/usr/src/cmd/print/gateway/adaptor.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/print/gateway/adaptor.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1998-2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -264,7 +263,7 @@
 
 
 int
-adaptor_client_access(const char *printer, const char *host)
+adaptor_client_access(const char *printer, const char *host, int peerfd)
 {
 	static int (*fpt)() = NULL;
 
@@ -272,7 +271,7 @@
 	    ((fpt = (int (*)())adaptor_function(paradigm_name,
 						"client_access")) != NULL))
 		return ((int)(fpt)((primary_name ? primary_name : printer),
-					host));
+					host, peerfd));
 
 	    return (-1);
 }
--- a/usr/src/cmd/print/gateway/adaptor.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/print/gateway/adaptor.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1998 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef _ADAPTOR_H
@@ -47,7 +46,8 @@
 extern	int  adaptor_available(const char *printer);
 extern	int  adaptor_spooler_available(const char *printer);
 extern	int  adaptor_spooler_accepting_jobs(const char *printer);
-extern  int  adaptor_client_access(const char *printer, const char *host);
+extern  int  adaptor_client_access(const char *printer, const char *host,
+				int peerfd);
 extern  int  adaptor_restart_printer(const char *printer);
 extern  char *adaptor_temp_dir(const char *printer, const char *host);
 extern  int  adaptor_submit_job(const char *printer, const char *host,
--- a/usr/src/cmd/print/gateway/main.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/print/gateway/main.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,7 +49,6 @@
 
 #include <adaptor.h>
 
-
 #define	ACK(fp)		{ (void) fputc(NULL, fp); (void) fflush(fp); }
 #define	NACK(fp)	{ (void) fputc('\001', fp); (void) fflush(fp); }
 
@@ -147,7 +145,6 @@
 	return (hostname);
 }
 
-
 static int
 request_id_no(const char *filename)
 {
@@ -559,7 +556,7 @@
 		exit(1);
 	}
 
-	if (adaptor_client_access(printer, host) < 0) {
+	if (adaptor_client_access(printer, host, fileno(ifp)) < 0) {
 		syslog(LOG_ERR, "%s doesn't have permission to talk to %s",
 			host, printer);
 		(void) fprintf(ofp,
--- a/usr/src/cmd/ptools/ppriv/ppriv.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/ptools/ppriv/ppriv.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Program to examine or set process privileges.
@@ -61,6 +60,7 @@
 static boolean_t	Don = B_FALSE;
 static boolean_t	Doff = B_FALSE;
 static boolean_t	list = B_FALSE;
+static boolean_t	mac_aware = B_FALSE;
 static int		mode = PRIV_STR_PORT;
 
 int
@@ -78,7 +78,7 @@
 	else
 		command = argv[0];
 
-	while ((opt = getopt(argc, argv, "lDNevs:S")) != EOF) {
+	while ((opt = getopt(argc, argv, "lDMNevs:S")) != EOF) {
 		switch (opt) {
 		case 'l':
 			list = B_TRUE;
@@ -87,6 +87,9 @@
 			set = B_TRUE;
 			Don = B_TRUE;
 			break;
+		case 'M':
+			mac_aware = B_TRUE;
+			break;
 		case 'N':
 			set = B_TRUE;
 			Doff = B_TRUE;
@@ -115,7 +118,8 @@
 	argc -= optind;
 	argv += optind;
 
-	if ((argc < 1 && !list) || Doff && Don || list && (set || exec))
+	if ((argc < 1 && !list) || Doff && Don || list && (set || exec) ||
+	    (mac_aware && !exec))
 		usage();
 
 	/*
@@ -314,7 +318,7 @@
 {
 	(void) fprintf(stderr,
 	    "usage:\t%s [-v] [-S] [-D|-N] [-s spec] { pid | core } ...\n"
-	    "\t%s -e [-D|-N] [-s spec] cmd [args ...]\n"
+	    "\t%s -e [-D|-N] [-M] [-s spec] cmd [args ...]\n"
 	    "\t%s -l [-v] [privilege ...]\n"
 	    "  (report, set or list process privileges)\n", command,
 	    command, command);
@@ -535,6 +539,13 @@
 {
 	int set;
 
+	if (mac_aware) {
+		if (setpflags(NET_MAC_AWARE, 1) != 0)
+			fatal("setpflags(NET_MAC_AWARE)");
+		if (setpflags(NET_MAC_AWARE_INHERIT, 1) != 0)
+			fatal("setpflags(NET_MAC_AWARE_INHERIT)");
+	}
+
 	if (sets != NULL) {
 		priv_set_t *target = priv_allocset();
 
--- a/usr/src/cmd/rpcbind/bind.xml	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/rpcbind/bind.xml	Fri Mar 24 12:29:20 2006 -0800
@@ -2,15 +2,15 @@
 <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
 
 <!--
- Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
+
  CDDL HEADER START
 
  The contents of this file are subject to the terms of the
- Common Development and Distribution License, Version 1.0 only
- (the "License").  You may not use this file except in compliance
- with the License.
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
 
  You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  or http://www.opensolaris.org/os/licensing.
@@ -25,6 +25,7 @@
 
  CDDL HEADER END
 
+
 	ident	"%Z%%M%	%I%	%E% SMI"
 
 	NOTE:  This service manifest is not editable; its contents will
@@ -93,7 +94,7 @@
 			<method_credential
 				user='root'
 				group='root'
-				privileges='basic,file_chown,file_chown_self,file_owner,net_privaddr,proc_setid,sys_nfs'
+				privileges='basic,file_chown,file_chown_self,file_owner,net_privaddr,proc_setid,sys_nfs,net_bindmlp'
 				/>
 		</method_context>
 	</exec_method>
--- a/usr/src/cmd/rpcbind/rpcbind.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/rpcbind/rpcbind.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -97,7 +96,9 @@
 
 static boolean_t check_hostserv(struct netconfig *, const char *, const char *);
 static void rpcb_check_init(void);
-
+static int setopt_reuseaddr(int);
+static int setopt_anon_mlp(int);
+static int setup_callit(int);
 
 /* Global variables */
 #ifdef ND_DEBUG
@@ -139,6 +140,7 @@
 	void *nc_handle;	/* Net config handle */
 	struct rlimit rl;
 	int maxrecsz = RPC_MAXDATASIZE;
+	boolean_t can_do_mlp;
 
 	parseargs(argc, argv);
 
@@ -167,8 +169,10 @@
 	 * These privileges are required for the t_bind check rpcbind uses
 	 * to determine whether a service is still live or not.
 	 */
+	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID,
-	    DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS, (char *)NULL) == -1) {
+	    DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS,
+	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 		fprintf(stderr, "Insufficient privileges\n");
 		exit(1);
 	}
@@ -399,9 +403,6 @@
 	int status;	/* bound checking ? */
 	static int msgprt = 0;
 
-	static int setopt_reuseaddr(int);
-	static int setup_callit(int);
-
 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
 		(nconf->nc_semantics != NC_TPI_COTS) &&
 		(nconf->nc_semantics != NC_TPI_COTS_ORD))
@@ -432,6 +433,14 @@
 		return (1);
 	}
 
+	if (is_system_labeled() &&
+	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+	    strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
+	    setopt_anon_mlp(fd) == -1) {
+		syslog(LOG_ERR, "%s: couldn't set SO_ANON_MLP option",
+		    nconf->nc_netid);
+	}
+
 	/*
 	 * Negotiate for returning the ucred of the caller. This should
 	 * done before enabling the endpoint for service via
@@ -769,28 +778,27 @@
 }
 
 static int
-setopt_reuseaddr(int fd)
+setopt_int(int fd, int level, int name, int value)
 {
 	struct t_optmgmt req, resp;
-	struct opthdr *opt;
-	char reqbuf[128];
-	int *ip;
+	struct {
+		struct opthdr opt;
+		int value;
+	} optdata;
 
-	opt = (struct opthdr *)reqbuf;
-	opt->level = SOL_SOCKET;
-	opt->name = SO_REUSEADDR;
-	opt->len = sizeof (int);
+	optdata.opt.level = level;
+	optdata.opt.name = name;
+	optdata.opt.len = sizeof (int);
 
-	ip = (int *)&reqbuf[sizeof (struct opthdr)];
-	*ip = 1;
+	optdata.value = value;
 
 	req.flags = T_NEGOTIATE;
-	req.opt.len = sizeof (struct opthdr) + opt->len;
-	req.opt.buf = (char *)opt;
+	req.opt.len = sizeof (optdata);
+	req.opt.buf = (char *)&optdata;
 
 	resp.flags = 0;
-	resp.opt.buf = reqbuf;
-	resp.opt.maxlen = sizeof (reqbuf);
+	resp.opt.buf = (char *)&optdata;
+	resp.opt.maxlen = sizeof (optdata);
 
 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
 		t_error("t_optmgmt");
@@ -800,6 +808,18 @@
 }
 
 static int
+setopt_reuseaddr(int fd)
+{
+	return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1));
+}
+
+static int
+setopt_anon_mlp(int fd)
+{
+	return (setopt_int(fd, SOL_SOCKET, SO_ANON_MLP, 1));
+}
+
+static int
 setup_callit(int fd)
 {
 	struct ipv6_mreq mreq;
--- a/usr/src/cmd/smserverd/myaudit.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/smserverd/myaudit.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2001-2002 Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,6 +38,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/smedia.h>
+#include <tsol/label.h>
 #include "smserver.h"
 #include <bsm/audit.h>
 #include <bsm/libbsm.h>
@@ -221,6 +220,10 @@
 			(void) au_write(ad, au_to_newgroups(ng, grplst));
 		}
 	}
+
+	if (is_system_labeled())
+		(void) au_write(ad, au_to_mylabel());
+
 	if (strlen(door_dp->audit_text) != 0) {
 		(void) au_write(ad, au_to_text(door_dp->audit_text));
 	}
--- a/usr/src/cmd/svc/shell/smf_include.sh	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/svc/shell/smf_include.sh	Fri Mar 24 12:29:20 2006 -0800
@@ -74,6 +74,17 @@
 	return 1
 }
 
+# smf_is_system_labeled
+#
+#  Returns zero (success) if system is labeled (aka Trusted Extensions).
+#  1 otherwise.
+#
+smf_is_system_labeled() {
+	[ ! -x /bin/plabel ] && return 1
+	/bin/plabel > /dev/null 2>&1
+	return $?
+}
+
 # smf_netstrategy
 #   -> (_INIT_NET_IF, _INIT_NET_STRATEGY)
 #
--- a/usr/src/cmd/tar/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/tar/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -35,7 +36,9 @@
 CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I../../lib/libcmd/inc
 DCFILE= $(PROG).dc
 
-LDLIBS += -lcmd -lsec
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += -lcmd -lsec $(LAZYLIBS)
 
 CFLAGS += $(CCVERBOSE)
 
--- a/usr/src/cmd/tar/tar.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/tar/tar.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -75,6 +74,11 @@
 #endif
 #include <archives.h>
 
+/* Trusted Extensions */
+#include <zone.h>
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
 /*
  * Source compatibility
  */
@@ -193,8 +197,6 @@
 	char	attr_info[1];
 } *attr;
 
-#define	ACL_HDR	'A'
-
 /*
  *
  * Tar has been changed to support extended attributes.
@@ -382,7 +384,7 @@
 static	struct	file_list	*exclude_tbl[TABLE_SIZE],
 				*include_tbl[TABLE_SIZE];
 
-static int	append_secattr(char **, int *, acl_t *);
+static int	append_secattr(char **, int *, int, char *, char);
 static void	write_ancillary(union hblock *, char *, int, char);
 
 static void add_file_to_table(struct file_list *table[], char *str);
@@ -464,7 +466,7 @@
 static int checkf(char *name, int mode, int howmuch);
 static int writetbuf(char *buffer, int n);
 static int wantit(char *argv[], char **namep, char **dirp, char **comp);
-
+static void append_ext_attr(char *shortname, char **secinfo, int *len);
 static int get_xdata(void);
 static void gen_num(const char *keyword, const u_longlong_t number);
 static void gen_date(const char *keyword, const timestruc_t time_value);
@@ -489,6 +491,15 @@
 static int put_xattr_hdr(char *longname, char *shortname, char *prefix,
     int typeflag, int filetype, struct linkbuf *lp);
 static int read_xattr_hdr();
+
+/* Trusted Extensions */
+#define	AUTO_ZONE	"/zone"
+
+static void extract_attr(char **file_ptr, struct sec_attr *);
+static int check_ext_attr(char *filename);
+static void rebuild_comp_path(char *str, char **namep);
+static int rebuild_lk_comp_path(char *str, char **namep);
+
 static void get_parent(char *path, char *dir);
 static char *get_component(char *path);
 static int retry_attrdir_open(char *name);
@@ -512,6 +523,22 @@
 static	int	Eflag;			/* Allow files greater than 8GB */
 static	int	atflag;			/* traverse extended attributes */
 static	int	Dflag;			/* Data change flag */
+/* Trusted Extensions */
+static	int	Tflag;			/* Trusted Extensions attr flags */
+static	int	dir_flag;		/* for attribute extract */
+static	int	mld_flag;		/* for attribute extract */
+static	char	*orig_namep;		/* original namep - unadorned */
+static	int	rpath_flag;		/* MLD real path is rebuilt */
+static	char	real_path[MAXPATHLEN];	/* MLD real path */
+static	int	lk_rpath_flag;		/* linked to real path is rebuilt */
+static	char	lk_real_path[MAXPATHLEN]; /* linked real path */
+static	bslabel_t	bs_label;	/* for attribute extract */
+static	bslabel_t	admin_low;
+static	bslabel_t	admin_high;
+static	int	ignored_aprivs = 0;
+static	int	ignored_fprivs = 0;
+static	int	ignored_fattrs = 0;
+
 static	int	term, chksum, wflag,
 		first = TRUE, defaults_used = FALSE, linkerrok;
 static	blkcnt_t	recno;
@@ -804,6 +831,10 @@
 			Eflag++;
 			Pflag++;	/* Only POSIX archive made */
 			break;
+		case 'T':
+			Tflag++;	/* Handle Trusted Extensions attrs */
+			pflag++;	/* also set flag for ACL */
+			break;
 		default:
 			(void) fprintf(stderr, gettext(
 			"tar: %c: unknown function modifier\n"), *cp);
@@ -825,6 +856,15 @@
 		"tar: specify only one of [ctxru].\n"));
 		usage();
 	}
+	/* Trusted Extensions attribute handling */
+	if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
+	    !is_system_labeled())) {
+		(void) fprintf(stderr, gettext(
+		"tar: the 'T' option is only available with "
+		    "Trusted Extensions\nand must be run from "
+		    "the global zone.\n"));
+		usage();
+	}
 	if (cflag && *argv == NULL && Filefile == NULL)
 		fatal(gettext("Missing filenames"));
 	if (usefile == NULL)
@@ -1000,9 +1040,9 @@
 	if (sysv3_env) {
 		(void) fprintf(stderr, gettext(
 #if defined(O_XATTR)
-		"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw@[0-7]][bfFk][X...] "
+		"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@[0-7]][bfFk][X...] "
 #else
-		"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqvw[0-7]][bfFk][X...] "
+		"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw[0-7]][bfFk][X...] "
 #endif
 		"[blocksize] [tarfile] [filename] [size] [exclude-file...] "
 		"{file | -I include-file | -C directory file}...\n"));
@@ -1011,9 +1051,9 @@
 	{
 		(void) fprintf(stderr, gettext(
 #if defined(O_XATTR)
-		"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw@[0-7]][bfk][X...] "
+		"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@[0-7]][bfk][X...] "
 #else
-		"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqvw[0-7]][bfk][X...] "
+		"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw[0-7]][bfk][X...] "
 #endif
 		"[blocksize] [tarfile] [size] [exclude-file...] "
 		"{file | -I include-file | -C directory file}...\n"));
@@ -2396,14 +2436,23 @@
 	int symflag;
 	int want;
 	acl_t	*aclp = NULL;	/* acl info */
+	char dot[] = ".";		/* dirp for using realpath */
 	timestruc_t	time_zero;	/* used for call to doDirTimes */
 	int		dircreate;
 	int convflag;
-	int cnt;
-
 	time_zero.tv_sec = 0;
 	time_zero.tv_nsec = 0;
 
+	/* reset Trusted Extensions variables */
+	rpath_flag = 0;
+	lk_rpath_flag = 0;
+	dir_flag = 0;
+	mld_flag = 0;
+	bslundef(&bs_label);
+	bsllow(&admin_low);
+	bslhigh(&admin_high);
+	orig_namep = 0;
+
 	dumping = 0;	/* for newvol(), et al:  we are not writing */
 
 	/*
@@ -2439,6 +2488,26 @@
 		if (want == -1)
 			break;
 
+/* Trusted Extensions */
+		/*
+		 * During tar extract (x):
+		 * If the pathname of the restored file has been
+		 * reconstructed from the ancillary file,
+		 * use it to process the normal file.
+		 */
+		if (mld_flag) {		/* Skip over .MLD. directory */
+			mld_flag = 0;
+			passtape();
+			continue;
+		}
+		orig_namep = namep;	/* save original */
+		if (rpath_flag) {
+			namep = real_path;	/* use zone path */
+			comp = real_path;	/* use zone path */
+			dirp = dot;		/* work from the top */
+			rpath_flag = 0;		/* reset */
+		}
+
 		if (dirfd != -1)
 			(void) close(dirfd);
 
@@ -2479,12 +2548,12 @@
 					xattr_linkp = NULL;
 					xattrhead = NULL;
 				} else {
-					fprintf(vfile,
+					(void) fprintf(vfile,
 					    gettext("tar: cannot open %s %s\n"),
 					    dirp, strerror(errno));
 				}
 #else
-				fprintf(vfile,
+				(void) fprintf(vfile,
 				    gettext("tar: cannot open %s %s\n"),
 				    dirp, strerror(errno));
 #endif
@@ -2724,7 +2793,10 @@
 			continue;
 		}
 		if (dblock.dbuf.typeflag == '2') {	/* symlink */
-			linkp = templink;
+			if ((Tflag) && (lk_rpath_flag == 1))
+				linkp = lk_real_path;
+			else
+				linkp = templink;
 			if (Aflag && *linkp == '/')
 				linkp++;
 			if (rmdir(namep) < 0) {
@@ -2864,6 +2936,15 @@
 			continue;
 		}
 
+		if (Tflag && (check_ext_attr(namep) == 0)) {
+			if (errflag)
+				done(1);
+			else
+				Errflg = 1;
+			passtape();
+			continue;
+		}
+
 		if (extno != 0) {	/* file is in pieces */
 			if (extotal < 1 || extotal > MAXEXT)
 				(void) fprintf(stderr, gettext(
@@ -2928,7 +3009,7 @@
 				ret = acl_set(namep, aclp);
 			}
 #else
-			ret = acl_set(namep, &aclp);
+			ret = acl_set(namep, aclp);
 #endif
 			if (ret < 0) {
 				if (pflag) {
@@ -2979,13 +3060,24 @@
 		}
 		xcnt++;			/* increment # files extracted */
 		}
-		if (dblock.dbuf.typeflag == 'A') { 	/* acl info */
+
+		/*
+		 * Process ancillary file.
+		 *
+		 */
+
+		if (dblock.dbuf.typeflag == 'A') {	/* acl info */
 			char	buf[TBLOCK];
 			char	*secp;
 			char	*tp;
 			int	attrsize;
 			int	cnt;
 
+			/* reset Trusted Extensions flags */
+			dir_flag = 0;
+			mld_flag = 0;
+			lk_rpath_flag = 0;
+			rpath_flag = 0;
 
 			if (pflag) {
 				bytes = stbuf.st_size;
@@ -2997,6 +3089,16 @@
 				}
 				tp = secp;
 				blocks = TBLOCKS(bytes);
+
+				/*
+				 * Display a line for each ancillary file.
+				 */
+				if (vflag && Tflag)
+					(void) fprintf(vfile, "x %s(A), %"
+					    FMT_blkcnt_t " bytes, %"
+					    FMT_blkcnt_t " tape blocks\n",
+					    namep, bytes, blocks);
+
 				while (blocks-- > 0) {
 					readtape(buf);
 					if (bytes <= TBLOCK) {
@@ -3049,7 +3151,23 @@
 						bytes -= attrsize;
 						break;
 
-					/* SunFed case goes here */
+					/* Trusted Extensions */
+
+					case DIR_TYPE:
+					case LBL_TYPE:
+					case APRIV_TYPE:
+					case FPRIV_TYPE:
+					case COMP_TYPE:
+					case LK_COMP_TYPE:
+					case ATTR_FLAG_TYPE:
+						attrsize =
+						    sizeof (struct sec_attr) +
+						    strlen(&attr->attr_info[0]);
+						bytes -= attrsize;
+						if (Tflag)
+							extract_attr(&namep,
+							    attr);
+						break;
 
 					default:
 						(void) fprintf(stderr, gettext(
@@ -5556,21 +5674,24 @@
 append_secattr(
 	char	 **secinfo,	/* existing security info */
 	int	 *secinfo_len,	/* length of existing security info */
-	acl_t	*aclp)
+	int	 size,		/* new attribute size: unit depends on type */
+	char	*attrtext,	/* new attribute text */
+	char	 attr_type)	/* new attribute type */
 {
 	char	*new_secinfo;
-	char	*attrtext;
 	int	newattrsize;
 	int	oldsize;
+	struct sec_attr	*attr;
 
 	/* no need to add */
-	if (aclp == (void *)NULL)
-		return (0);
-
-	switch (acl_type(aclp)) {
-	case ACLENT_T:
-	case ACE_T:
-		attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
+	if (attr_type != DIR_TYPE) {
+		if (attrtext == NULL)
+			return (0);
+	}
+
+	switch (attr_type) {
+	case UFSD_ACL:
+	case ACE_ACL:
 		if (attrtext == NULL) {
 			(void) fprintf(stderr, "acltotext failed\n");
 			return (-1);
@@ -5582,15 +5703,28 @@
 			(void) fprintf(stderr, "can't allocate memory\n");
 			return (-1);
 		}
-		attr->attr_type = (acl_type(aclp) == ACLENT_T) ?
-		    UFSD_ACL : ACE_ACL;
+		attr->attr_type = attr_type;
 		(void) sprintf(attr->attr_len,
-		    "%06o", acl_cnt(aclp)); /* acl entry count */
+		    "%06o", size); /* acl entry count */
 		(void) strcpy((char *)&attr->attr_info[0], attrtext);
 		free(attrtext);
 		break;
 
-	/* SunFed's case goes here */
+	/* Trusted Extensions */
+	case DIR_TYPE:
+	case LBL_TYPE:
+		newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
+		attr = (struct sec_attr *)malloc(newattrsize);
+		if (attr == NULL) {
+			(void) fprintf(stderr,
+			gettext("can't allocate memory\n"));
+			return (-1);
+		}
+		attr->attr_type = attr_type;
+		(void) sprintf(attr->attr_len,
+		    "%06d", size); /* len of attr data */
+		(void) strcpy((char *)&attr->attr_info[0], attrtext);
+		break;
 
 	default:
 		(void) fprintf(stderr, "unrecognized attribute type\n");
@@ -5604,6 +5738,7 @@
 	if (new_secinfo == NULL) {
 		(void) fprintf(stderr, "can't allocate memory\n");
 		*secinfo_len -= newattrsize;
+		free(attr);
 		return (-1);
 	}
 
@@ -5611,6 +5746,7 @@
 	(void) memcpy(new_secinfo + oldsize, attr, newattrsize);
 
 	free(*secinfo);
+	free(attr);
 	*secinfo = new_secinfo;
 	return (0);
 }
@@ -6779,7 +6915,17 @@
 
 		/* append security attributes if any */
 		if (aclp != NULL) {
-			(void) append_secattr(&secinfo, &len, aclp);
+			(void) append_secattr(&secinfo, &len, acl_cnt(aclp),
+			    acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT),
+			    (acl_type(aclp) == ACLENT_T) ? UFSD_ACL : ACE_ACL);
+		}
+
+		if (Tflag) {
+			/* append Trusted Extensions extended attributes */
+			append_ext_attr(shortname, &secinfo, &len);
+			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
+
+		} else if (aclp != NULL) {
 			(void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
 		}
 	}
@@ -7160,3 +7306,629 @@
 		}
 	}
 }
+/* Trusted Extensions */
+
+/*
+ * append_ext_attr():
+ *
+ * Append extended attributes and other information into the buffer
+ * that gets written to the ancillary file.
+ *
+ * With option 'T', we create a tarfile which
+ * has an ancillary file each corresponding archived file.
+ * Each ancillary file contains 1 or more of the
+ * following attributes:
+ *
+ *	attribute type        attribute		process procedure
+ *	----------------      ----------------  --------------------------
+ *   	DIR_TYPE       = 'D'   directory flag	append if a directory
+ *    	LBL_TYPE       = 'L'   SL[IL] or SL	append ascii label
+ *
+ *
+ */
+static void
+append_ext_attr(char *shortname, char **secinfo, int *len)
+{
+	bslabel_t	b_slabel;	/* binary sensitvity label */
+	char		*ascii = NULL;	/* ascii label */
+
+	/*
+	 * For each attribute type, append it if it is
+	 * relevant to the file type.
+	 */
+
+	/*
+	 * For attribute type DIR_TYPE,
+	 * append it to the following file type:
+	 *
+	 *	S_IFDIR: directories
+	 */
+
+	/*
+	 * For attribute type LBL_TYPE,
+	 * append it to the following file type:
+	 *
+	 *	S_IFDIR: directories (including mld, sld)
+	 *	S_IFLNK: symbolic link
+	 *	S_IFREG: regular file but not hard link
+	 *	S_IFIFO: FIFO file but not hard link
+	 *	S_IFCHR: char special file but not hard link
+	 *	S_IFBLK: block special file but not hard link
+	 */
+	switch (stbuf.st_mode & S_IFMT) {
+
+	case S_IFDIR:
+
+		/*
+		 * append DIR_TYPE
+		 */
+		(void) append_secattr(secinfo, len, 1,
+			"\0", DIR_TYPE);
+
+		/*
+		 * Get and append attribute types LBL_TYPE.
+		 * For directories, LBL_TYPE contains SL.
+		 */
+		/* get binary sensitivity label */
+		if (getlabel(shortname, &b_slabel) != 0) {
+			(void) fprintf(stderr,
+			    gettext("tar: can't get sensitvity label for "
+			    " %s, getlabel() error: %s\n"),
+			    shortname, strerror(errno));
+		} else {
+			/* get ascii SL */
+			if (bsltos(&b_slabel, &ascii,
+			    0, 0) <= 0) {
+				(void) fprintf(stderr,
+				    gettext("tar: can't get ascii SL for"
+				    " %s\n"), shortname);
+			} else {
+				/* append LBL_TYPE */
+				(void) append_secattr(secinfo, len,
+				    strlen(ascii) + 1, ascii,
+				    LBL_TYPE);
+
+				/* free storage */
+				if (ascii != NULL) {
+					free(ascii);
+					ascii = (char *)0;
+				}
+			}
+
+		}
+		break;
+
+	case S_IFLNK:
+	case S_IFREG:
+	case S_IFIFO:
+	case S_IFCHR:
+	case S_IFBLK:
+
+		/* get binary sensitivity label */
+		if (getlabel(shortname, &b_slabel) != 0) {
+			(void) fprintf(stderr,
+			    gettext("tar: can't get sensitivty label for %s, "
+			    "getlabel() error: %s\n"),
+			    shortname, strerror(errno));
+		} else {
+			/* get ascii IL[SL] */
+			if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
+				(void) fprintf(stderr,
+				    gettext("tar: can't translate sensitivity "
+				    " label for %s\n"), shortname);
+			} else {
+				char *cmw_label;
+				size_t  cmw_length;
+
+				cmw_length = strlen("ADMIN_LOW [] ") +
+				    strlen(ascii);
+				if ((cmw_label = malloc(cmw_length)) == NULL) {
+					(void) fprintf(stderr, gettext(
+					    "Insufficient memory for label\n"));
+					exit(1);
+				}
+				/* append LBL_TYPE */
+				(void) snprintf(cmw_label, cmw_length,
+				    "ADMIN_LOW [%s]", ascii);
+				(void) append_secattr(secinfo, len,
+				    strlen(cmw_label) + 1, cmw_label,
+				    LBL_TYPE);
+
+				/* free storage */
+				if (ascii != NULL) {
+					free(cmw_label);
+					free(ascii);
+					ascii = (char *)0;
+				}
+			}
+		}
+		break;
+
+	default:
+		break;
+	} /* end switch for LBL_TYPE */
+
+
+	/* DONE !! */
+	return;
+
+} /* end of append_ext_attr */
+
+
+/*
+ *	Name: extract_attr()
+ *
+ *	Description:
+ *		Process attributes from the ancillary file due to
+ *		the T option.
+ *
+ *	Call by doxtract() as part of the switch case structure.
+ *	Making this a separate routine because the nesting are too
+ *	deep in doxtract, thus, leaving very little space
+ *	on each line for instructions.
+ *
+ * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
+ *
+ * For option 'T', following are possible attributes in
+ * a TS 8 ancillary file: (NOTE: No IL support)
+ *
+ *	attribute type        attribute		process procedure
+ *	----------------      ----------------  -------------------------
+ *    #	LBL_TYPE       = 'L'   SL               construct binary label
+ *    #	APRIV_TYPE     = 'P'   allowed priv    	construct privileges
+ *    #	FPRIV_TYPE     = 'p'   forced priv	construct privileges
+ *    #	COMP_TYPE      = 'C'   path component	construct real path
+ *    #	DIR_TYPE       = 'D'   directory flag	note it is a directory
+ *    $	UFSD_ACL       = '1'   ACL data		construct ACL entries
+ *	ATTR_FLAG_TYPE = 'F'   file attr flags  construct binary flags
+ *	LK_COMP_TYPE   = 'K'   linked path comp construct linked real path
+ *
+ * note: # = attribute names common between TS 8 & TS 2.5 ancillary
+ *           files.
+ *       $ = ACL attribute is processed for the option 'p', it doesn't
+ *           need option 'T'.
+ *
+ * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
+ *
+ */
+static void
+extract_attr(char **file_ptr, struct sec_attr *attr)
+{
+	int	reterr, err;
+	char	*dummy_buf;	/* for attribute extract */
+
+	dummy_buf = attr->attr_info;
+
+	switch (attr->attr_type) {
+
+	case DIR_TYPE:
+
+		dir_flag++;
+		break;
+
+	case LBL_TYPE:
+
+		/*
+		 * LBL_TYPE is used to indicate SL for directory, and
+		 * CMW label for other file types.
+		 */
+
+		if (!dir_flag) { /* not directory */
+			/* Skip over IL portion */
+			char *sl_ptr = strchr(dummy_buf, '[');
+
+			if (sl_ptr == NULL)
+				err = 0;
+			else
+				err = stobsl(sl_ptr, &bs_label,
+				    NEW_LABEL, &reterr);
+		} else { /* directory */
+			err = stobsl(dummy_buf, &bs_label,
+			    NEW_LABEL, &reterr);
+		}
+		if (err == 0) {
+			(void) fprintf(stderr, gettext("tar: "
+			    "can't convert %s to binary label\n"),
+			    dummy_buf);
+			bslundef(&bs_label);
+		} else if (!blequal(&bs_label, &admin_low) &&
+		    !blequal(&bs_label, &admin_high)) {
+			bslabel_t *from_label;
+			char *buf;
+			char tempbuf[MAXPATHLEN];
+
+			if (*orig_namep != '/') {
+				/* got relative linked to path */
+				(void) getcwd(tempbuf, (sizeof (tempbuf)));
+				(void) strncat(tempbuf, "/", MAXPATHLEN);
+			} else
+				*tempbuf = '\0';
+
+			buf = real_path;
+			(void) strncat(tempbuf, orig_namep, MAXPATHLEN);
+			from_label = getlabelbypath(tempbuf);
+			if (from_label != NULL) {
+				if (blequal(from_label, &admin_low)) {
+					if ((getpathbylabel(tempbuf, buf,
+					    MAXPATHLEN, &bs_label) == NULL)) {
+						(void) fprintf(stderr,
+						    gettext("tar: "
+						"can't get zone root path for "
+						"%s\n"), tempbuf);
+					} else
+						rpath_flag = 1;
+				}
+				free(from_label);
+			}
+		}
+		break;
+
+	case COMP_TYPE:
+
+		rebuild_comp_path(dummy_buf, file_ptr);
+		break;
+
+	case LK_COMP_TYPE:
+
+		if (rebuild_lk_comp_path(dummy_buf, file_ptr)
+		    == 0) {
+			lk_rpath_flag = 1;
+		} else {
+			(void) fprintf(stderr, gettext("tar: warning: link's "
+			    "target pathname might be invalid.\n"));
+			lk_rpath_flag = 0;
+		}
+		break;
+	case APRIV_TYPE:
+		ignored_aprivs++;
+		break;
+	case FPRIV_TYPE:
+		ignored_fprivs++;
+		break;
+	case ATTR_FLAG_TYPE:
+		ignored_fattrs++;
+		break;
+
+	default:
+
+		break;
+	}
+
+	/* done */
+	return;
+
+}	/* end extract_attr */
+
+
+
+/*
+ *	Name:	rebuild_comp_path()
+ *
+ *	Description:
+ *		Take the string of components passed down by the calling
+ *		routine and parse the values and rebuild the path.
+ *		This routine no longer needs to produce a new real_path
+ *		string because it is produced when the 'L' LABEL_TYPE is
+ *		interpreted. So the only thing done here is to distinguish
+ *		between an SLD and an MLD entry. We only want one, so we
+ *		ignore the MLD entry by setting the mld_flag.
+ *
+ *	return value:
+ *		none
+ */
+static void
+rebuild_comp_path(char *str, char **namep)
+{
+	char		*cp;
+
+	while (*str != '\0') {
+
+		switch (*str) {
+
+		case MLD_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+				str = cp + 2;
+				*cp = ';';
+			}
+			mld_flag = 1;
+			break;
+
+		case SLD_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+				str = cp + 2;
+				*cp = ';';
+			}
+			mld_flag = 0;
+			break;
+
+		case PATH_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+				str = cp + 2;
+				*cp = ';';
+			}
+			break;
+		}
+	}
+	if (rpath_flag)
+		*namep = real_path;
+	return;
+
+} /* end rebuild_comp_path() */
+
+/*
+ *	Name:	rebuild_lk_comp_path()
+ *
+ *	Description:
+ *		Take the string of components passed down by the calling
+ *		routine and parse the values and rebuild the path.
+ *
+ *	return value:
+ *		0 = succeeded
+ *		-1 = failed
+ */
+static int
+rebuild_lk_comp_path(char *str, char **namep)
+{
+	char		*cp;
+	int		reterr;
+	bslabel_t	bslabel;
+	char		*buf;
+	char		pbuf[MAXPATHLEN];
+	char		*ptr1, *ptr2;
+	int		plen;
+	int		use_pbuf;
+	char		tempbuf[MAXPATHLEN];
+	int		mismatch;
+	bslabel_t	*from_label;
+	char		zonename[ZONENAME_MAX];
+	zoneid_t	zoneid;
+
+	/* init stuff */
+	use_pbuf = 0;
+	mismatch = 0;
+
+	/*
+	 * For linked to pathname (LK_COMP_TYPE):
+	 *  - If the linked to pathname is absolute (start with /), we
+	 *    will use it as is.
+	 *  - If it is a relative pathname then it is relative to 1 of 2
+	 *    directories.  For a hardlink, it is relative to the current
+	 *    directory.  For a symbolic link, it is relative to the
+	 *    directory the symbolic link is in.  For the symbolic link
+	 *    case, set a flag to indicate we need to use the prefix of
+	 *    the restored file's pathname with the linked to pathname.
+	 *
+	 *    NOTE: At this point, we have no way to determine if we have
+	 *    a hardlink or a symbolic link.  We will compare the 1st
+	 *    component in the prefix portion of the restore file's
+	 *    pathname to the 1st component in the attribute data
+	 *    (the linked pathname).  If they are the same, we will assume
+	 *    the link pathname to reconstruct is relative to the current
+	 *    directory.  Otherwise, we will set a flag indicate we need
+	 *    to use a prefix with the reconstructed name.  Need to compare
+	 *    both the adorned and unadorned version before deciding a
+	 *    mismatch.
+	 */
+
+	buf = lk_real_path;
+	if (*(str + 1) != '/') { /* got relative linked to path */
+		ptr1 = orig_namep;
+		ptr2 = strrchr(ptr1, '/');
+		plen = ptr2 - ptr1;
+		if (plen > 0) {
+			pbuf[0] = '\0';
+			plen++;		/* include '/' */
+			(void) strncpy(pbuf, ptr1, plen);
+			*(pbuf + plen) = '\0';
+			ptr2 = strchr(pbuf, '/');
+			if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
+				mismatch = 1;
+		}
+
+		if (mismatch == 1)
+			use_pbuf = 1;
+	}
+
+	buf[0] = '\0';
+
+	while (*str != '\0') {
+
+		switch (*str) {
+
+		case MLD_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+
+				/*
+				 * Ignore attempts to backup over .MLD.
+				 */
+				if (strcmp(str, "../") != 0)
+					(void) strncat(buf, str, MAXPATHLEN);
+				str = cp + 2;
+				*cp = ';';
+			}
+			break;
+
+		case SLD_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+
+				/*
+				 * Use the path name in the header if
+				 * error occurs when processing the
+				 * SLD type.
+				 */
+
+				if (!stobsl(str, &bslabel,
+				    NO_CORRECTION, &reterr)) {
+					(void) fprintf(stderr, gettext(
+					    "tar: can't translate to binary"
+					    "SL for SLD, stobsl() error:"
+					    " %s\n"), strerror(errno));
+					return (-1);
+				}
+
+				str = cp + 2;
+				*cp = ';';
+
+				if (use_pbuf == 1) {
+					if (*pbuf != '/') {
+						/* relative linked to path */
+
+						(void) getcwd(tempbuf,
+						    (sizeof (tempbuf)));
+						(void) strncat(tempbuf, "/",
+						    MAXPATHLEN);
+						(void) strncat(tempbuf, pbuf,
+						    MAXPATHLEN);
+					}
+					else
+						(void) strcpy(tempbuf, pbuf);
+
+				} else if (*buf != '/') {
+					/* got relative linked to path */
+
+					(void) getcwd(tempbuf,
+					    (sizeof (tempbuf)));
+					(void) strncat(tempbuf, "/",
+					    MAXPATHLEN);
+				} else
+					*tempbuf = '\0';
+
+				(void) strncat(tempbuf, buf, MAXPATHLEN);
+				*buf = '\0';
+
+				if (blequal(&bslabel, &admin_high)) {
+					bslabel = admin_low;
+				}
+
+
+				/*
+				 * Check for cross-zone symbolic links
+				 */
+				from_label = getlabelbypath(real_path);
+				if (rpath_flag && (from_label != NULL) &&
+				    !blequal(&bslabel, from_label)) {
+					if ((zoneid =
+					    getzoneidbylabel(&bslabel)) == -1) {
+						(void) fprintf(stderr,
+						    gettext("tar: can't get "
+							"zone ID for %s\n"),
+						    tempbuf);
+						return (-1);
+					}
+					if (zone_getattr(zoneid, ZONE_ATTR_NAME,
+					    &zonename, ZONENAME_MAX) == -1) {
+						/* Badly configured zone info */
+						(void) fprintf(stderr,
+						    gettext("tar: can't get "
+							"zonename for %s\n"),
+						    tempbuf);
+						return (-1);
+					}
+					(void) strncpy(buf, AUTO_ZONE,
+					    MAXPATHLEN);
+					(void) strncat(buf, "/",
+					    MAXPATHLEN);
+					(void) strncat(buf, zonename,
+					    MAXPATHLEN);
+				}
+				if (from_label != NULL)
+					free(from_label);
+				(void) strncat(buf, tempbuf, MAXPATHLEN);
+				break;
+			}
+			mld_flag = 0;
+			break;
+
+		case PATH_TYPE:
+
+			str++;
+			if ((cp = strstr(str, ";;")) != NULL) {
+				*cp = '\0';
+				(void) strncat(buf, str, MAXPATHLEN);
+				str = cp + 2;
+				*cp = ';';
+			}
+			break;
+
+		default:
+
+			(void) fprintf(stderr, gettext(
+				"tar: error rebuilding path %s\n"),
+				*namep);
+			*buf = '\0';
+			str++;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Done for LK_COMP_TYPE
+	 */
+
+	return (0);    /* component path is rebuilt successfully */
+
+} /* end rebuild_lk_comp_path() */
+
+/*
+ *	Name: check_ext_attr()
+ *
+ *	Description:
+ *		Check the extended attributes for a file being extracted.
+ *		The attributes being checked here are CMW labels.
+ *		ACLs are not set here because they are set by the
+ *		pflag in doxtract().
+ *
+ *		If the label doesn't match, return 0
+ *		else return 1
+ */
+static int
+check_ext_attr(char *filename)
+{
+	bslabel_t	currentlabel;	/* label from zone */
+
+	if (bltype(&bs_label, SUN_SL_UN)) {
+		/* No label check possible */
+		return (0);
+	}
+	if (getlabel(filename, &currentlabel) != 0) {
+		(void) fprintf(stderr,
+		    gettext("tar: can't get label for "
+			" %s, getlabel() error: %s\n"),
+			filename, strerror(errno));
+		return (0);
+	} else if ((blequal(&currentlabel, &bs_label)) == 0) {
+		char	*src_label = NULL;	/* ascii label */
+
+		/* get current src SL */
+		if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
+			(void) fprintf(stderr,
+			    gettext("tar: can't interpret requested label for"
+				" %s\n"), filename);
+		} else {
+			(void) fprintf(stderr,
+			    gettext("tar: can't apply label %s to %s\n"),
+				src_label, filename);
+			free(src_label);
+		}
+		(void) fprintf(stderr,
+		    gettext("tar: %s not restored\n"), filename);
+		return (0);
+	}
+	return (1);
+
+}	/* end check_ext_attr */
--- a/usr/src/cmd/truss/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/truss/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -40,7 +39,9 @@
 CFLAGS		+= $(CCVERBOSE)
 CFLAGS64	+= $(CCVERBOSE)
 
-LDLIBS	+= -lproc -lrtld_db -lc_db -lnsl -lsocket
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS	+= -lproc -lrtld_db -lc_db -lnsl -lsocket $(LAZYLIBS)
 
 CPPFLAGS += -D_REENTRANT -D_LARGEFILE64_SOURCE=1
 
--- a/usr/src/cmd/truss/expound.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/truss/expound.c	Fri Mar 24 12:29:20 2006 -0800
@@ -90,6 +90,7 @@
 #include <sys/zone.h>
 #include <sys/priv_impl.h>
 #include <sys/priv.h>
+#include <tsol/label.h>
 
 #include "ramdata.h"
 #include "systable.h"
@@ -4440,6 +4441,33 @@
 		(void) printf("%s\textended_error: 0x%p\n", pri->pname,
 		    (void *)args.extended_error);
 
+		if (is_system_labeled()) {
+			char		*label_str = NULL;
+			bslabel_t	zone_label;
+
+			(void) printf("%s\t         match: %d\n", pri->pname,
+			    args.match);
+			(void) printf("%s\t           doi: %d\n", pri->pname,
+			    args.doi);
+
+			if (Pread_string(Proc, (char *)&zone_label,
+			    sizeof (zone_label), (uintptr_t)args.label) != -1) {
+				/* show the label as string */
+				if (label_to_str(&zone_label, &label_str,
+				    M_LABEL, SHORT_NAMES) != 0) {
+					/* have to dump label as raw string */
+					(void) label_to_str(&zone_label,
+					    &label_str, M_INTERNAL,
+					    SHORT_NAMES);
+				}
+			}
+
+			(void) printf("%s\t         label: %s\n",
+			    pri->pname, label_str != NULL ? label_str : "<?>");
+			if (label_str)
+				free(label_str);
+		}
+
 		if (args.zfsbufsz > 0)
 			free(zone_zfs);
 	}
@@ -4495,6 +4523,32 @@
 		(void) printf("%s\textended_error: 0x%x\n", pri->pname,
 		    (caddr32_t)args.extended_error);
 
+		if (is_system_labeled()) {
+			char		*label_str = NULL;
+			bslabel_t	zone_label;
+
+			(void) printf("%s\t         match: %d\n", pri->pname,
+			    args.match);
+			(void) printf("%s\t           doi: %d\n", pri->pname,
+			    args.doi);
+
+			if (Pread_string(Proc, (char *)&zone_label,
+			    sizeof (zone_label), (caddr32_t)args.label) != -1) {
+				/* show the label as string */
+				if (label_to_str(&zone_label, &label_str,
+				    M_LABEL, SHORT_NAMES) != 0) {
+					/* have to dump label as raw string */
+					(void) label_to_str(&zone_label,
+					    &label_str, M_INTERNAL,
+					    SHORT_NAMES);
+				}
+			}
+			(void) printf("%s\t         label: %s\n",
+			    pri->pname, label_str != NULL ? label_str : "<?>");
+			if (label_str)
+				free(label_str);
+		}
+
 		if (args.zfsbufsz > 0)
 			free(zone_zfs);
 	}
--- a/usr/src/cmd/truss/print.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/truss/print.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -77,6 +76,7 @@
 #include <sys/utrap.h>
 #include <sys/lgrp_user.h>
 #include <sys/door.h>
+#include <sys/tsol/tndb.h>
 #include "ramdata.h"
 #include "print.h"
 #include "proto.h"
@@ -2310,6 +2310,7 @@
 		case ZONE_ATTR_UNIQID:	s = "ZONE_ATTR_UNIQID"; break;
 		case ZONE_ATTR_POOLID:	s = "ZONE_ATTR_POOLID"; break;
 		case ZONE_ATTR_INITPID:	s = "ZONE_ATTR_INITPID"; break;
+		case ZONE_ATTR_SLBL:	s = "ZONE_ATTR_SLBL"; break;
 		}
 	}
 
@@ -2332,6 +2333,30 @@
 }
 
 /*
+ * Print Trusted Networking database operation codes (labelsys; tn*)
+ */
+static void
+prt_tnd(private_t *pri, int raw, long val)
+{
+	const char *s = NULL;
+
+	if (!raw) {
+		switch ((tsol_dbops_t)val) {
+		case TNDB_NOOP:		s = "TNDB_NOOP";	break;
+		case TNDB_LOAD:		s = "TNDB_LOAD";	break;
+		case TNDB_DELETE:	s = "TNDB_DELETE";	break;
+		case TNDB_FLUSH:	s = "TNDB_FLUSH";	break;
+		case TNDB_GET:		s = "TNDB_GET";		break;
+		}
+	}
+
+	if (s == NULL)
+		prt_dec(pri, 0, val);
+	else
+		outstring(pri, s);
+}
+
+/*
  * Print LIO_XX flags
  */
 void
@@ -2501,5 +2526,6 @@
 	prt_lio,	/* LIO -- print LIO_XX flags */
 	prt_dfl,	/* DFL -- print door_create() flags */
 	prt_dpm,	/* DPM -- print DOOR_PARAM_XX flags */
+	prt_tnd,	/* TND -- print trusted network data base opcode */
 	prt_dec,	/* HID -- hidden argument, make this the last one */
 };
--- a/usr/src/cmd/truss/print.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/truss/print.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -128,7 +127,8 @@
 #define	LIO	85		/* print LIO_XX flags */
 #define	DFL	86		/* print door_create() flags */
 #define	DPM	87		/* print DOOR_PARAM_XX flags */
-#define	HID	88		/* hidden argument, don't print */
+#define	TND	88		/* print trusted network data base opcode */
+#define	HID	89		/* hidden argument, don't print */
 				/* make sure HID is always the last member */
 
 /*
--- a/usr/src/cmd/truss/systable.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/truss/systable.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -410,7 +409,7 @@
 {"rusagesys",	2, DEC, NOV, DEC, HEX},				/* 181 */
 {"portfs",	6, HEX, HEX, DEC, HEX, HEX, HEX, HEX, HEX},	/* 182 */
 {"pollsys",	4, DEC, NOV, HEX, DEC, HEX, HEX},		/* 183 */
-{ NULL,		8, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX, HEX},
+{"labelsys",	2, DEC, NOV, DEC, HEX},				/* 184 */
 {"acl",		4, DEC, NOV, STG, ACL, DEC, HEX},		/* 185 */
 {"auditsys",	4, DEC, NOV, AUD, HEX, HEX, HEX},		/* 186 */
 {"processor_bind", 4, DEC, NOV, IDT, DEC, DEC, HEX},		/* 187 */
@@ -793,6 +792,17 @@
 };
 #define	NZONECODE	(sizeof (zonetable) / sizeof (struct systable))
 
+static const struct systable labeltable[] = {
+{"labelsys", 3, DEC, NOV, HID, HEX, HEX},			/* 0 */
+{"is_system_labeled", 1, DEC, NOV, HID},			/* 1 */
+{"tnrh", 3, DEC, NOV, HID, TND, HEX},				/* 2 */
+{"tnrhtp", 3, DEC, NOV, HID, TND, HEX},				/* 3 */
+{"tnmlp", 3, DEC, NOV, HID, TND, HEX},				/* 4 */
+{"getlabel", 3, DEC, NOV, HID, STG, HEX},			/* 5 */
+{"fgetlabel", 3, DEC, NOV, HID, DEC, HEX},			/* 6 */
+};
+#define	NLABELCODE	(sizeof (labeltable) / sizeof (struct systable))
+
 const	struct sysalias sysalias[] = {
 	{ "exit",	SYS_exit	},
 	{ "fork",	SYS_fork1	},
@@ -928,10 +938,15 @@
 	{ "getzoneid",		SYS_zone	},
 	{ "zone_list",		SYS_zone	},
 	{ "zone_shutdown",	SYS_zone	},
+	{ "is_system_labeled",	SYS_labelsys	},
+	{ "tnrh",		SYS_labelsys	},
+	{ "tnrhtp",		SYS_labelsys	},
+	{ "tnmlp",		SYS_labelsys	},
+	{ "getlabel",		SYS_labelsys	},
+	{ "fgetlabel",		SYS_labelsys	},
 	{  NULL,	0	}	/* end-of-list */
 };
 
-
 /*
  * Return structure to interpret system call with sub-codes.
  */
@@ -1062,6 +1077,10 @@
 			if ((unsigned)subcode < NZONECODE)
 				stp = &zonetable[subcode];
 			break;
+		case SYS_labelsys:	/* label family */
+			if ((unsigned)subcode < NLABELCODE)
+				stp = &labeltable[subcode];
+			break;
 		}
 	}
 
@@ -1212,6 +1231,7 @@
 		case SYS_rusagesys:	/* rusagesys */
 		case SYS_ucredsys:	/* ucredsys */
 		case SYS_zone:		/* zone */
+		case SYS_labelsys:	/* labelsys */
 			subcode = arg0;
 			break;
 		case SYS_fcntl:		/* fcntl() */
@@ -1271,7 +1291,8 @@
 		+ NPRIVSYSCODE - 1
 		+ NUCREDSYSCODE - 1
 		+ NPORTCODE - 1
-		+ NZONECODE - 1);
+		+ NZONECODE - 1
+		+ NLABELCODE - 1);
 }
 
 /*
@@ -1341,6 +1362,8 @@
 		return (NPORTCODE);
 	case SYS_zone:		/* zone */
 		return (NZONECODE);
+	case SYS_labelsys:
+		return (NLABELCODE);
 	default:
 		return (1);
 	}
--- a/usr/src/cmd/volmgt/rmm/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/volmgt/rmm/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -54,7 +54,7 @@
 
 CPPFLAGS += 	-DACT_VERS=${ACT_VERS} -DIDENT_VERS=${IDENT_VERS}
 
-$(PROG) :=	LDLIBS += -lvolmgt -ladm
+$(PROG) :=	LDLIBS += -lvolmgt -ladm -lcontract
 $(ACTSVOL) :=	LDLIBS += -lvolmgt
 $(ACTS) :=	LDLIBS += -lc
 
--- a/usr/src/cmd/volmgt/rmm/rmm.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/volmgt/rmm/rmm.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,6 +31,7 @@
 #include	<fcntl.h>
 #include	<dirent.h>
 #include	<string.h>
+#include	<strings.h>
 #include	<errno.h>
 #include	<rmmount.h>
 #include	<locale.h>
@@ -46,6 +47,11 @@
 #include	<string.h>
 #include	<regex.h>
 #include	<ctype.h>
+#include	<zone.h>
+#include	<libcontract.h>
+#include	<sys/contract/process.h>
+#include	<sys/ctfs.h>
+#include	<pwd.h>
 #include	"rmm_int.h"
 
 extern int	audio_only(struct action_arg *);
@@ -66,6 +72,13 @@
 char			*prog_name = NULL;
 pid_t			prog_pid = 0;
 
+int		system_labeled = 0;
+uid_t		mnt_uid = -1;
+gid_t		mnt_gid = -1;
+zoneid_t	mnt_zoneid = -1;
+char		mnt_zoneroot[MAXPATHLEN];
+char		mnt_userdir[MAXPATHLEN];
+
 #define	DEFAULT_CONFIG	"/etc/rmmount.conf"
 #define	DEFAULT_DSODIR	"/usr/lib/rmmount"
 
@@ -160,6 +173,8 @@
 	char			*volume_path;
 	char			*volume_pcfs_id;
 	char			*volume_symdev;
+	char			*volume_zonename;
+	char			*volume_user;
 
 	/*
 	 * Make sure core files appear in a volmgt directory.
@@ -190,6 +205,10 @@
 		return (-1);
 	}
 
+	system_labeled = is_system_labeled();
+	mnt_zoneroot[0] = '\0';
+	mnt_userdir[0] = '\0';
+
 	while ((c = getopt(argc, argv, "d:c:D")) != EOF) {
 		switch (c) {
 		case 'D':
@@ -216,6 +235,11 @@
 	volume_pcfs_id = getenv("VOLUME_PCFS_ID");
 	volume_symdev = getenv("VOLUME_SYMDEV");
 
+	if (system_labeled) {
+		volume_zonename = getenv("VOLUME_ZONE_NAME");
+		volume_user = getenv("VOLUME_USER");
+	}
+
 	if (volume_action == NULL) {
 		dprintf("%s(%ld): VOLUME_ACTION was null!!\n",
 		    prog_name, prog_pid);
@@ -248,6 +272,43 @@
 		return (-1);
 	}
 
+	if (system_labeled) {
+		if (volume_zonename != NULL &&
+		    strcmp(volume_zonename, GLOBAL_ZONENAME) != 0) {
+			if ((mnt_zoneid =
+			    getzoneidbyname(volume_zonename)) != -1) {
+				if (zone_getattr(mnt_zoneid, ZONE_ATTR_ROOT,
+				    mnt_zoneroot, MAXPATHLEN) == -1) {
+					dprintf("%s(%ld): NO ZONEPATH!!\n",
+					    prog_name, prog_pid);
+					return (-1);
+				}
+			}
+		} else {
+			mnt_zoneid = GLOBAL_ZONEID;
+			mnt_zoneroot[0] = '\0';
+		}
+		if (volume_user != NULL) {
+			struct passwd	 *pw;
+
+			if ((pw = getpwnam(volume_user)) == NULL) {
+				dprintf("%s(%ld) %s\n", prog_name, prog_pid,
+				    ": VOLUME_USER was not a valid user!");
+				return (-1);
+			}
+			mnt_uid = pw->pw_uid;
+			mnt_gid = pw->pw_gid;
+
+			if (snprintf(mnt_userdir, sizeof (mnt_userdir),
+			    "/%s-%s", volume_user, volume_symdev) >=
+			    sizeof (mnt_userdir))
+				return (-1);
+		} else {
+			mnt_uid = 0;
+			mnt_userdir[0] = '\0';
+		}
+	}
+
 	dprintf("%s[%d]: VOLUME_NAME = %s\n", __FILE__, __LINE__, volume_name);
 	dprintf("%s[%d]: VOLUME_PATH = %s\n", __FILE__, __LINE__, volume_path);
 	dprintf("%s[%d]: VOLUME_ACTION = %s\n", __FILE__, __LINE__,
@@ -260,6 +321,12 @@
 		volume_mount_mode);
 	dprintf("%s[%d]: VOLUME_PCFS_ID = %s\n", __FILE__, __LINE__,
 		volume_pcfs_id);
+	if (system_labeled) {
+		dprintf("%s[%d]: VOLUME_ZONE_NAME = %s\n", __FILE__, __LINE__,
+		    volume_zonename);
+		dprintf("%s[%d]: VOLUME_USER = %s\n", __FILE__, __LINE__,
+		    volume_user);
+	}
 
 	/*
 	 * Read in the configuration file to build
@@ -318,7 +385,11 @@
 		}
 		ai = 0;
 		while ((aa[ai] != NULL) && (aa[ai]->aa_path != NULL)) {
-			aa[ai]->aa_type = "unknown";
+			if (system_labeled &&
+			    (strcmp(volume_mediatype, "rmdisk") == 0))
+				aa[ai]->aa_type = "pcfs";
+			else
+				aa[ai]->aa_type = "unknown";
 			ai++;
 		}
 	}
@@ -688,20 +759,76 @@
 				action_list[i]->a_action = act_func;
 			}
 			if (act_func != NULL) {
-				dprintf("%s[%d]: executing action() in %s\n",
-					__FILE__, __LINE__,
-					action_list[i]->a_dsoname);
-				retval = (*act_func)(aa,
-					action_list[i]->a_argc,
-					action_list[i]->a_argv);
-				dprintf("%s[%d]: action() returns %d\n",
-					__FILE__, __LINE__, retval);
+			    if (!premount && mnt_zoneid > GLOBAL_ZONEID) {
+				pid_t	pid;
+				int	status;
+				int	ifx;
+				int	tmpl_fd;
+				int err = 0;
+
+				tmpl_fd = open64(CTFS_ROOT "/process/template",
+				    O_RDWR);
+				if (tmpl_fd == -1)
+					break;
+
 				/*
-				 * If action returns 0, no further actions
-				 * will be executed. (see rmmount.conf(4))
+				 * Deliver no events, don't inherit,
+				 * and allow it to be orphaned.
 				 */
-				if (retval == 0)
+				err |= ct_tmpl_set_critical(tmpl_fd, 0);
+				err |= ct_tmpl_set_informative(tmpl_fd, 0);
+				err |= ct_pr_tmpl_set_fatal(tmpl_fd,
+				    CT_PR_EV_HWERR);
+				err |= ct_pr_tmpl_set_param(tmpl_fd,
+				    CT_PR_PGRPONLY |
+				    CT_PR_REGENT);
+				if (err || ct_tmpl_activate(tmpl_fd)) {
+					(void) close(tmpl_fd);
+					break;
+				}
+				switch (pid = fork1()) {
+				case 0:
+					(void) ct_tmpl_clear(tmpl_fd);
+					for (ifx = 0; ifx < _NFILE; ifx++)
+						(void) close(ifx);
+
+					if (zone_enter(mnt_zoneid) == -1)
+						_exit(0);
+					(void) (*act_func)(aa,
+						action_list[i]->a_argc,
+						action_list[i]->a_argv);
+					_exit(0);
+				case -1:
+					dprintf("fork1 failed \n ");
 					break;
+				default :
+					(void) ct_tmpl_clear(tmpl_fd);
+					(void) close(tmpl_fd);
+					if (waitpid(pid, &status, 0) < 0) {
+						dprintf("%s(%ld): waitpid() "
+						    "failed (errno %d) \n",
+						    prog_name, prog_pid, errno);
+						break;
+					}
+				    }
+				} else {
+					dprintf("%s[%d]: executing action() "
+					    "in %s\n",
+					    __FILE__, __LINE__,
+					    action_list[i]->a_dsoname);
+					retval = (*act_func)(aa,
+						action_list[i]->a_argc,
+						action_list[i]->a_argv);
+					dprintf("%s[%d]: action() returns %d\n",
+					    __FILE__, __LINE__, retval);
+					/*
+					 * If action returns 0, no further
+					 * actions will be executed.
+					 * (see rmmount.conf(4))
+					 */
+					if (retval == 0)
+						break;
+				}
 			}
 		}
 		i++;
@@ -874,7 +1001,6 @@
 				if (aa[ai]->aa_mountpoint)
 					mnt_ai = ai;
 			}
-
 			if (ma[CMD_SHARE] != NULL) {
 				/*
 				 * export the file system.
@@ -904,10 +1030,17 @@
 			(void) symlink(aa[mnt_ai]->aa_mountpoint, symname);
 		}
 #else	/* !OLD_SLICE_HANDLING_CODE */
-		(void) snprintf(symcontents, sizeof (symcontents),
-			"./%s", name);
-		(void) snprintf(symname, sizeof (symname),
-			"/%s/%s", aa[mnt_ai]->aa_media, symdev);
+		if (system_labeled) {
+			(void) snprintf(symcontents, sizeof (symcontents),
+			    ".%s/%s", mnt_userdir, name);
+			(void) snprintf(symname, sizeof (symname), "%s/%s/%s",
+			    mnt_zoneroot, aa[mnt_ai]->aa_media, symdev);
+		} else {
+			(void) snprintf(symcontents, sizeof (symcontents),
+			    "./%s", name);
+			(void) snprintf(symname, sizeof (symname),
+			    "/%s/%s", aa[mnt_ai]->aa_media, symdev);
+		}
 		(void) unlink(symname);
 		(void) symlink(symcontents, symname);
 #endif	/* !OLD_SLICE_HANDLING_CODE */
@@ -957,10 +1090,9 @@
 
 		dprintf("%s[%d]: mount path = %s\n",
 			__FILE__, __LINE__, mnt_path);
+		if ((mountpoint = getmntpoint(mnt_path)) == NULL)
+			continue;
 
-		if ((mountpoint = getmntpoint(mnt_path)) == NULL) {
-			continue;
-		}
 		/*
 		 * find the right mount arguments for this device
 		 */
@@ -1006,7 +1138,6 @@
 		if (ma != NULL) {
 			unshare_mount(aa[ai], ma);
 		}
-
 		/*
 		 * do the actual umount
 		 */
@@ -1020,13 +1151,11 @@
 		}
 
 		/* save a good mountpoint */
-		if (oldmountpoint == NULL) {
+		if (oldmountpoint == NULL)
 			oldmountpoint = strdup(mountpoint);
-		}
 		free(mountpoint);
 		mountpoint = NULL;
 	}
-
 	/*
 	 * clean up our directories and such if all went well
 	 */
@@ -1053,28 +1182,60 @@
 		 * try to remove the symlink
 		 */
 
-		if (snprintf(rmm_mountpoint, sizeof (rmm_mountpoint),
-			"/%s/%s", aa[0]->aa_media, volume_name)
-				>= sizeof (rmm_mountpoint))
-			success = FALSE;
-
-		if (success && (oldmountpoint != NULL) &&
-		    (strcmp(oldmountpoint, rmm_mountpoint) == 0)) {
+		if (system_labeled) {
+			/* Prefix with zoneroot and userdir */
+			if (snprintf(rmm_mountpoint, MAXPATHLEN, "%s/%s%s/%s",
+			    mnt_zoneroot, aa[0]->aa_media, mnt_userdir,
+			    volume_name) >= MAXPATHLEN)
+				success = FALSE;
+		} else {
+			if (snprintf(rmm_mountpoint, sizeof (rmm_mountpoint),
+			    "/%s/%s", aa[0]->aa_media, volume_name)
+			    >= sizeof (rmm_mountpoint))
+				success = FALSE;
+		}
+		if ((system_labeled && success) ||
+		(success && (oldmountpoint != NULL) &&
+		    (strcmp(oldmountpoint, rmm_mountpoint) == 0))) {
 			char    symname[MAXNAMELEN];
 
 			/* remove volmgt mount point */
-			(void) rmdir(oldmountpoint);
+			if (oldmountpoint)
+				(void) rmdir(oldmountpoint);
+			if (system_labeled && (strlen(mnt_userdir) > 0)) {
+				char *p = NULL;
+
+				/*
+				 * We may also need to remove the
+				 * user's private directory which
+				 * we created during mount.
+				 */
+				(void) rmdir(rmm_mountpoint);
+				if (p = rindex(rmm_mountpoint, '/')) {
+					*p = '\0';
+					(void) rmdir(rmm_mountpoint);
+				}
+			}
 
 			/* remove symlink (what harm if it does not exist?) */
-			if (snprintf(symname, sizeof (symname), "/%s/%s",
-				aa[0]->aa_media, symdev) >= sizeof (symname)) {
-				success = FALSE;
+			if (system_labeled) {
+				/* Prefix with zoneroot */
+				if (snprintf(symname, sizeof (symname),
+				    "%s/%s/%s",
+				    mnt_zoneroot, aa[0]->aa_media, symdev)
+				    >= sizeof (symname))
+					success = FALSE;
+			} else {
+				if (snprintf(symname, sizeof (symname),
+				    "/%s/%s",
+				    aa[0]->aa_media, symdev)
+				    >= sizeof (symname))
+					success = FALSE;
 			}
 			if (success)
 				(void) unlink(symname);
 		}
 	}
-
 	if (oldmountpoint != NULL) {
 		free(oldmountpoint);
 	}
@@ -1249,7 +1410,8 @@
 	 */
 	char		*targ_dir;
 	char		options[RMM_OPTSTRLEN];	/* mount option string */
-	char		*mountpoint = NULL;
+	char		mountpoint[MAXPATHLEN];
+	char		*zonemountpoint;
 	int		mountpoint_bufcount = 0;
 	struct stat 	sb;
 	mode_t		mpmode;
@@ -1330,33 +1492,45 @@
 		return (FALSE);
 	}
 
+	if (system_labeled && (strlen(mnt_userdir) > 0)) {
+		if (snprintf(mountpoint, MAXPATHLEN, "%s/%s%s",
+		    mnt_zoneroot, aa->aa_media, mnt_userdir) > MAXPATHLEN) {
+			return (FALSE);
+
+		}
+		(void) makepath(mountpoint, 0700);
+		(void) chown(mountpoint, mnt_uid, mnt_gid);
+		/*
+		 * set the top level directory bits to 0755 so user
+		 * can access it.
+		 */
+		if (snprintf(mountpoint, MAXPATHLEN, "%s/%s", mnt_zoneroot,
+		    aa->aa_media) <= MAXPATHLEN)
+			(void) chmod(mountpoint, 0755);
+	}
+
 	if (aa->aa_partname) {
-		mountpoint_bufcount = strlen(aa->aa_media) +
-			strlen(targ_dir) + strlen(aa->aa_partname) + 3 + 1;
-		/* 1 - for NULL terminator, 3 - for "/"s */
-		mountpoint = malloc(mountpoint_bufcount);
-		if (mountpoint == NULL) {
+		if (snprintf(mountpoint, MAXPATHLEN,
+		    "%s/%s%s/%s/%s", mnt_zoneroot, aa->aa_media, mnt_userdir,
+		    targ_dir, aa->aa_partname) > MAXPATHLEN) {
+			(void) fprintf(stderr,
+				gettext("%s(%ld) error: path too long\n"),
+				prog_name, prog_pid);
+			return (FALSE);
+		}
+	} else {
+		if (snprintf(mountpoint, MAXPATHLEN,
+		    "%s/%s%s/%s", mnt_zoneroot, aa->aa_media, mnt_userdir,
+		    targ_dir) > MAXPATHLEN) {
 			(void) fprintf(stderr,
 				gettext("%s(%ld) error: malloc failed\n"),
 				prog_name, prog_pid);
 			return (FALSE);
 		}
-		(void) sprintf(mountpoint, "/%s/%s/%s", aa->aa_media,
-		    targ_dir, aa->aa_partname);
-	} else {
-		mountpoint_bufcount = strlen(aa->aa_media) +
-			strlen(targ_dir) + 2 + 1;
-		/* 1 - for NULL terminator, 2 - for "/"s */
-		mountpoint = malloc(mountpoint_bufcount);
-		if (mountpoint == NULL) {
-			(void) fprintf(stderr,
-				gettext("%s(%ld) error: malloc failed\n"),
-				prog_name, prog_pid);
-			return (FALSE);
-		}
-		(void) sprintf(mountpoint, "/%s/%s", aa->aa_media, targ_dir);
 	}
 
+	zonemountpoint = mountpoint + strlen(mnt_zoneroot);
+
 	/* make our mountpoint */
 	(void) makepath(mountpoint, 0755);
 
@@ -1455,7 +1629,7 @@
 			    prog_name, prog_pid, mountpoint, options);
 		}
 		aa->aa_mnt = TRUE;
-		aa->aa_mountpoint = strdup(mountpoint);
+		aa->aa_mountpoint = strdup(zonemountpoint);
 		dprintf(
 		"\nDEBUG: Setting u.g of \"%s\" to %d.%d (me=%d.%d)\n\n",
 		    mountpoint, sb.st_uid, sb.st_gid, getuid(), getgid());
@@ -1489,9 +1663,6 @@
 		(void) rmdir(mountpoint);			/* cleanup */
 		ret_val = FALSE;
 	}
-	if (mountpoint != NULL)
-		free(mountpoint);
-
 	return (ret_val);
 }
 
--- a/usr/src/cmd/zoneadm/zoneadm.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/zoneadm/zoneadm.c	Fri Mar 24 12:29:20 2006 -0800
@@ -398,7 +398,7 @@
 static int
 lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
 {
-	char root[MAXPATHLEN];
+	char root[MAXPATHLEN], *cp;
 	int err;
 
 	(void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
@@ -407,13 +407,33 @@
 
 	zent->zid = zid;
 
-	if ((err = zone_get_zonepath(zent->zname, root, sizeof (root))) !=
-	    Z_OK) {
-		errno = err;
-		zperror2(zent->zname, gettext("could not get zone path"));
-		return (Z_ERR);
-	}
-	(void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
+	/*
+	 * For labeled zones which query the zone path of lower-level
+	 * zones, the path needs to be adjusted to drop the final
+	 * "/root" component. This adjusted path is then useful
+	 * for reading down any exported directories from the
+	 * lower-level zone.
+	 */
+	if (is_system_labeled() && zent->zid != ZONE_ID_UNDEFINED) {
+		if (zone_getattr(zent->zid, ZONE_ATTR_ROOT, zent->zroot,
+		    sizeof (zent->zroot)) == -1) {
+			zperror2(zent->zname,
+			    gettext("could not get zone path."));
+			return (Z_ERR);
+		}
+		cp = zent->zroot + strlen(zent->zroot) - 5;
+		if (cp > zent->zroot && strcmp(cp, "/root") == 0)
+			*cp = 0;
+	} else {
+		if ((err = zone_get_zonepath(zent->zname, root,
+		    sizeof (root))) != Z_OK) {
+			errno = err;
+			zperror2(zent->zname,
+			    gettext("could not get zone path."));
+			return (Z_ERR);
+		}
+		(void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
+	}
 
 	if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) {
 		errno = err;
@@ -1342,7 +1362,12 @@
 	 */
 	result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname));
 	assert(result >= 0);
-	(void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
+	if (!is_system_labeled()) {
+		(void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
+	} else {
+		(void) zone_getattr(zid, ZONE_ATTR_ROOT, zeptr->zroot,
+		    sizeof (zeptr->zroot));
+	}
 	zeptr->zstate_str = "running";
 }
 
@@ -1395,7 +1420,7 @@
 			    cmd_to_str(CMD_LIST));
 			return (Z_ERR);
 		}
-		if (zone_id == GLOBAL_ZONEID) {
+		if (zone_id == GLOBAL_ZONEID || is_system_labeled()) {
 			retv = zone_print_list(min_state, verbose, parsable);
 		} else {
 			retv = Z_OK;
@@ -3024,6 +3049,14 @@
 	}
 
 	/*
+	 * Trusted Extensions requires that cloned zones use the
+	 * same sysid configuration, so it is not appropriate to
+	 * unconfigure the zone.
+	 */
+	if (is_system_labeled())
+		return (Z_OK);
+
+	/*
 	 * Check if the zone is already sys-unconfiged.  This saves us
 	 * the work of bringing up the scratch zone so we can unconfigure it.
 	 */
--- a/usr/src/cmd/zoneadmd/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/zoneadmd/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 
 #
@@ -38,8 +40,10 @@
 POFILES= $(OBJS:%.o=%.po)
 
 CFLAGS += $(CCVERBOSE)
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
 LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair -lpool \
-	-lgen -lbsm -lcontract -lzfs
+	-lgen -lbsm -lcontract -lzfs -ltsnet $(LAZYLIBS)
 XGETFLAGS += -a -x zoneadmd.xcl
 
 .KEEP_STATE:
--- a/usr/src/cmd/zoneadmd/vplat.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/cmd/zoneadmd/vplat.c	Fri Mar 24 12:29:20 2006 -0800
@@ -106,6 +106,9 @@
 
 #include <libzonecfg.h>
 #include "zoneadmd.h"
+#include <tsol/label.h>
+#include <libtsnet.h>
+#include <sys/priv.h>
 
 #define	V4_ADDR_LEN	32
 #define	V6_ADDR_LEN	128
@@ -118,6 +121,7 @@
 	MNTOPT_RO "," MNTOPT_LOFS_NOSUB "," MNTOPT_NODEVICES
 
 #define	DFSTYPES	"/etc/dfs/fstypes"
+#define	MAXTNZLEN	2048
 
 /*
  * A list of directories which should be created.
@@ -176,6 +180,14 @@
 /* array of cached mount entries for resolve_lofs */
 static struct mnttab *resolve_lofs_mnts, *resolve_lofs_mnt_max;
 
+/* for Trusted Extensions */
+static tsol_zcent_t *get_zone_label(zlog_t *, priv_set_t *);
+static int tsol_mounts(zlog_t *, char *, char *);
+static void tsol_unmounts(zlog_t *, char *);
+static m_label_t *zlabel = NULL;
+static m_label_t *zid_label = NULL;
+static priv_set_t *zprivs = NULL;
+
 /* from libsocket, not in any header file */
 extern int getnetmaskbyaddr(struct in_addr, struct in_addr *);
 
@@ -457,8 +469,24 @@
 		 * and we don't need to second guess him.
 		 */
 		if (!S_ISDIR(st.st_mode)) {
-			zerror(zlogp, B_FALSE, "%s is not a directory", path);
-			return (-1);
+			if (is_system_labeled() &&
+			    S_ISREG(st.st_mode)) {
+				/*
+				 * The need to mount readonly copies of
+				 * global zone /etc/ files is unique to
+				 * Trusted Extensions.
+				 */
+				if (strncmp(subdir, "/etc/",
+				    strlen("/etc/")) != 0) {
+					zerror(zlogp, B_FALSE,
+					    "%s is not in /etc", path);
+					return (-1);
+				}
+			} else {
+				zerror(zlogp, B_FALSE,
+				    "%s is not a directory", path);
+				return (-1);
+			}
 		}
 	} else if (mkdirp(path, mode) != 0) {
 		if (errno == EROFS)
@@ -690,6 +718,12 @@
 	(void) strcat(zroot, "/");
 	zrootlen = strlen(zroot);
 
+	/*
+	 * For Trusted Extensions unmount each higher level zone's mount
+	 * of our zone's /export/home
+	 */
+	tsol_unmounts(zlogp, zone_name);
+
 	if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
 		zerror(zlogp, B_TRUE, "failed to open %s", MNTTAB);
 		return (-1);
@@ -959,8 +993,23 @@
 		return (-1);
 	}
 	if (!S_ISDIR(statbuf.st_mode)) {
-		zerror(zlogp, B_FALSE, "%s is not a directory", path);
-		return (-1);
+		if (is_system_labeled() && S_ISREG(statbuf.st_mode)) {
+			/*
+			 * The need to mount readonly copies of
+			 * global zone /etc/ files is unique to
+			 * Trusted Extensions.
+			 * The check for /etc/ via strstr() is to
+			 * allow paths like $ZONEROOT/etc/passwd
+			 */
+			if (strstr(path, "/etc/") == NULL) {
+				zerror(zlogp, B_FALSE,
+				    "%s is not in /etc", path);
+				return (-1);
+			}
+		} else {
+			zerror(zlogp, B_FALSE, "%s is not a directory", path);
+			return (-1);
+		}
 	}
 	if ((res = resolvepath(path, respath, sizeof (respath))) == -1) {
 		zerror(zlogp, B_TRUE, "unable to resolve path %s", path);
@@ -1476,6 +1525,13 @@
 		if (mount_one(zlogp, &fs_ptr[i], rootpath) != 0)
 			goto bad;
 	}
+
+	/*
+	 * For Trusted Extensions cross-mount each lower level /export/home
+	 */
+	if (tsol_mounts(zlogp, zone_name, rootpath) != 0)
+		goto bad;
+
 	free_fs_data(fs_ptr, num_fs);
 
 	/*
@@ -2706,6 +2762,507 @@
 	return (0);
 }
 
+/*
+ * Mount lower level home directories into/from current zone
+ * Share exported directories specified in dfstab for zone
+ */
+static int
+tsol_mounts(zlog_t *zlogp, char *zone_name, char *rootpath)
+{
+	zoneid_t *zids = NULL;
+	priv_set_t *zid_privs;
+	const priv_impl_info_t *ip = NULL;
+	uint_t nzents_saved;
+	uint_t nzents;
+	int i;
+	char readonly[] = "ro";
+	struct zone_fstab lower_fstab;
+	char *argv[4];
+
+	if (!is_system_labeled())
+		return (0);
+
+	if (zid_label == NULL) {
+		zid_label = m_label_alloc(MAC_LABEL);
+		if (zid_label == NULL)
+			return (-1);
+	}
+
+	/* Make sure our zone has an /export/home dir */
+	(void) make_one_dir(zlogp, rootpath, "/export/home",
+	    DEFAULT_DIR_MODE);
+
+	lower_fstab.zone_fs_raw[0] = '\0';
+	(void) strlcpy(lower_fstab.zone_fs_type, MNTTYPE_LOFS,
+	    sizeof (lower_fstab.zone_fs_type));
+	lower_fstab.zone_fs_options = NULL;
+	(void) zonecfg_add_fs_option(&lower_fstab, readonly);
+
+	/*
+	 * Get the list of zones from the kernel
+	 */
+	if (zone_list(NULL, &nzents) != 0) {
+		zerror(zlogp, B_TRUE, "unable to list zones");
+		zonecfg_free_fs_option_list(lower_fstab.zone_fs_options);
+		return (-1);
+	}
+again:
+	if (nzents == 0) {
+		zonecfg_free_fs_option_list(lower_fstab.zone_fs_options);
+		return (-1);
+	}
+
+	zids = malloc(nzents * sizeof (zoneid_t));
+	if (zids == NULL) {
+		zerror(zlogp, B_TRUE, "unable to allocate memory");
+		return (-1);
+	}
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		zerror(zlogp, B_TRUE, "unable to list zones");
+		zonecfg_free_fs_option_list(lower_fstab.zone_fs_options);
+		free(zids);
+		return (-1);
+	}
+	if (nzents != nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	ip = getprivimplinfo();
+	if ((zid_privs = priv_allocset()) == NULL) {
+		zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
+		zonecfg_free_fs_option_list(
+		    lower_fstab.zone_fs_options);
+		free(zids);
+		return (-1);
+	}
+
+	for (i = 0; i < nzents; i++) {
+		char zid_name[ZONENAME_MAX];
+		zone_state_t zid_state;
+		char zid_rpath[MAXPATHLEN];
+		struct stat stat_buf;
+
+		if (zids[i] == GLOBAL_ZONEID)
+			continue;
+
+		if (getzonenamebyid(zids[i], zid_name, ZONENAME_MAX) == -1)
+			continue;
+
+		/*
+		 * Do special setup for the zone we are booting
+		 */
+		if (strcmp(zid_name, zone_name) == 0) {
+			struct zone_fstab autofs_fstab;
+			char map_path[MAXPATHLEN];
+			int fd;
+
+			/*
+			 * Create auto_home_<zone> map for this zone
+			 * in the global zone. The local zone entry
+			 * will be created by automount when the zone
+			 * is booted.
+			 */
+
+			(void) snprintf(autofs_fstab.zone_fs_special,
+			    MAXPATHLEN, "auto_home_%s", zid_name);
+
+			(void) snprintf(autofs_fstab.zone_fs_dir, MAXPATHLEN,
+			    "/zone/%s/home", zid_name);
+
+			(void) snprintf(map_path, sizeof (map_path),
+			    "/etc/%s", autofs_fstab.zone_fs_special);
+			/*
+			 * If the map file doesn't exist create a template
+			 */
+			if ((fd = open(map_path, O_RDWR | O_CREAT | O_EXCL,
+			    S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) {
+				int len;
+				char map_rec[MAXPATHLEN];
+
+				len = snprintf(map_rec, sizeof (map_rec),
+				    "+%s\n*\t-fstype=lofs\t:%s/export/home/&\n",
+				    autofs_fstab.zone_fs_special, rootpath);
+				(void) write(fd, map_rec, len);
+				(void) close(fd);
+			}
+
+			/*
+			 * Mount auto_home_<zone> in the global zone if absent.
+			 * If it's already of type autofs, then
+			 * don't mount it again.
+			 */
+			if ((stat(autofs_fstab.zone_fs_dir, &stat_buf) == -1) ||
+			    strcmp(stat_buf.st_fstype, MNTTYPE_AUTOFS) != 0) {
+				char optstr[] = "indirect,ignore,nobrowse";
+
+				(void) make_one_dir(zlogp, "",
+				    autofs_fstab.zone_fs_dir, DEFAULT_DIR_MODE);
+
+				/*
+				 * Mount will fail if automounter has already
+				 * processed the auto_home_<zonename> map
+				 */
+				(void) domount(zlogp, MNTTYPE_AUTOFS, optstr,
+				    autofs_fstab.zone_fs_special,
+				    autofs_fstab.zone_fs_dir);
+			}
+			continue;
+		}
+
+
+		if (zone_get_state(zid_name, &zid_state) != Z_OK ||
+		    (zid_state != ZONE_STATE_MOUNTED &&
+		    zid_state != ZONE_STATE_RUNNING)) {
+
+			/* Skip over zones without mounted filesystems */
+			continue;
+		}
+
+		if (zone_getattr(zids[i], ZONE_ATTR_SLBL, zid_label,
+		    sizeof (m_label_t)) < 0)
+			/* Skip over zones with unspecified label */
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_ROOT, zid_rpath,
+		    sizeof (zid_rpath)) == -1)
+			/* Skip over zones with bad path */
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_PRIVSET, zid_privs,
+		    sizeof (priv_chunk_t) * ip->priv_setsize) == -1)
+			/* Skip over zones with bad privs */
+			continue;
+
+		/*
+		 * Reading down is valid according to our label model
+		 * but some customers want to disable it because it
+		 * allows execute down and other possible attacks.
+		 * Therefore, we restrict this feature to zones that
+		 * have the NET_MAC_AWARE privilege which is required
+		 * for NFS read-down semantics.
+		 */
+		if ((bldominates(zlabel, zid_label)) &&
+		    (priv_ismember(zprivs, PRIV_NET_MAC_AWARE))) {
+			/*
+			 * Our zone dominates this one.
+			 * Create a lofs mount from lower zone's /export/home
+			 */
+			(void) snprintf(lower_fstab.zone_fs_dir, MAXPATHLEN,
+			    "%s/zone/%s/export/home", rootpath, zid_name);
+
+			/*
+			 * If the target is already an LOFS mount
+			 * then don't do it again.
+			 */
+			if ((stat(lower_fstab.zone_fs_dir, &stat_buf) == -1) ||
+			    strcmp(stat_buf.st_fstype, MNTTYPE_LOFS) != 0) {
+
+				if (snprintf(lower_fstab.zone_fs_special,
+				    MAXPATHLEN, "%s/export",
+				    zid_rpath) > MAXPATHLEN)
+					continue;
+
+				/*
+				 * Make sure the lower-level home exists
+				 */
+				if (make_one_dir(zlogp,
+				    lower_fstab.zone_fs_special,
+				    "/home", DEFAULT_DIR_MODE) != 0)
+					continue;
+
+				(void) strlcat(lower_fstab.zone_fs_special,
+				    "/home", MAXPATHLEN);
+
+				/*
+				 * Mount can fail because the lower-level
+				 * zone may have already done a mount up.
+				 */
+				(void) mount_one(zlogp, &lower_fstab, "");
+			}
+		} else if ((bldominates(zid_label, zlabel)) &&
+		    (priv_ismember(zid_privs, PRIV_NET_MAC_AWARE))) {
+			/*
+			 * This zone dominates our zone.
+			 * Create a lofs mount from our zone's /export/home
+			 */
+			if (snprintf(lower_fstab.zone_fs_dir, MAXPATHLEN,
+			    "%s/zone/%s/export/home", zid_rpath,
+			    zone_name) > MAXPATHLEN)
+				continue;
+
+			/*
+			 * If the target is already an LOFS mount
+			 * then don't do it again.
+			 */
+			if ((stat(lower_fstab.zone_fs_dir, &stat_buf) == -1) ||
+			    strcmp(stat_buf.st_fstype, MNTTYPE_LOFS) != 0) {
+
+				(void) snprintf(lower_fstab.zone_fs_special,
+				    MAXPATHLEN, "%s/export/home", rootpath);
+
+				/*
+				 * Mount can fail because the higher-level
+				 * zone may have already done a mount down.
+				 */
+				(void) mount_one(zlogp, &lower_fstab, "");
+			}
+		}
+	}
+	zonecfg_free_fs_option_list(lower_fstab.zone_fs_options);
+	priv_freeset(zid_privs);
+	free(zids);
+
+	/*
+	 * Now share any exported directories from this zone.
+	 * Each zone can have its own dfstab.
+	 */
+
+	argv[0] = "zoneshare";
+	argv[1] = "-z";
+	argv[2] = zone_name;
+	argv[3] = NULL;
+
+	(void) forkexec(zlogp, "/usr/lib/zones/zoneshare", argv);
+	/* Don't check for errors since they don't affect the zone */
+
+	return (0);
+}
+
+/*
+ * Unmount lofs mounts from higher level zones
+ * Unshare nfs exported directories
+ */
+static void
+tsol_unmounts(zlog_t *zlogp, char *zone_name)
+{
+	zoneid_t *zids = NULL;
+	uint_t nzents_saved;
+	uint_t nzents;
+	int i;
+	char *argv[4];
+	char path[MAXPATHLEN];
+
+	if (!is_system_labeled())
+		return;
+
+	/*
+	 * Get the list of zones from the kernel
+	 */
+	if (zone_list(NULL, &nzents) != 0) {
+		return;
+	}
+
+	if (zid_label == NULL) {
+		zid_label = m_label_alloc(MAC_LABEL);
+		if (zid_label == NULL)
+			return;
+	}
+
+again:
+	if (nzents == 0)
+		return;
+
+	zids = malloc(nzents * sizeof (zoneid_t));
+	if (zids == NULL) {
+		zerror(zlogp, B_TRUE, "unable to allocate memory");
+		return;
+	}
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		free(zids);
+		return;
+	}
+	if (nzents != nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	for (i = 0; i < nzents; i++) {
+		char zid_name[ZONENAME_MAX];
+		zone_state_t zid_state;
+		char zid_rpath[MAXPATHLEN];
+
+		if (zids[i] == GLOBAL_ZONEID)
+			continue;
+
+		if (getzonenamebyid(zids[i], zid_name, ZONENAME_MAX) == -1)
+			continue;
+
+		/*
+		 * Skip the zone we are halting
+		 */
+		if (strcmp(zid_name, zone_name) == 0)
+			continue;
+
+		if ((zone_getattr(zids[i], ZONE_ATTR_STATUS, &zid_state,
+		    sizeof (zid_state)) < 0) ||
+		    (zid_state < ZONE_IS_READY))
+			/* Skip over zones without mounted filesystems */
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_SLBL, zid_label,
+		    sizeof (m_label_t)) < 0)
+			/* Skip over zones with unspecified label */
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_ROOT, zid_rpath,
+		    sizeof (zid_rpath)) == -1)
+			/* Skip over zones with bad path */
+			continue;
+
+		if (zlabel != NULL && bldominates(zid_label, zlabel)) {
+			/*
+			 * This zone dominates our zone.
+			 * Unmount the lofs mount of our zone's /export/home
+			 */
+
+			if (snprintf(path, MAXPATHLEN,
+			    "%s/zone/%s/export/home", zid_rpath,
+			    zone_name) > MAXPATHLEN)
+				continue;
+
+			/* Skip over mount failures */
+			(void) umount(path);
+		}
+	}
+	free(zids);
+
+	/*
+	 * Unmount global zone autofs trigger for this zone
+	 */
+	(void) snprintf(path, MAXPATHLEN, "/zone/%s/home", zone_name);
+	/* Skip over mount failures */
+	(void) umount(path);
+
+	/*
+	 * Next unshare any exported directories from this zone.
+	 */
+
+	argv[0] = "zoneunshare";
+	argv[1] = "-z";
+	argv[2] = zone_name;
+	argv[3] = NULL;
+
+	(void) forkexec(zlogp, "/usr/lib/zones/zoneunshare", argv);
+	/* Don't check for errors since they don't affect the zone */
+
+	/*
+	 * Finally, deallocate any devices in the zone.
+	 */
+
+	argv[0] = "deallocate";
+	argv[1] = "-Isz";
+	argv[2] = zone_name;
+	argv[3] = NULL;
+
+	(void) forkexec(zlogp, "/usr/sbin/deallocate", argv);
+	/* Don't check for errors since they don't affect the zone */
+}
+
+/*
+ * Fetch the Trusted Extensions label and multi-level ports (MLPs) for
+ * this zone.
+ */
+static tsol_zcent_t *
+get_zone_label(zlog_t *zlogp, priv_set_t *privs)
+{
+	FILE *fp;
+	tsol_zcent_t *zcent = NULL;
+	char line[MAXTNZLEN];
+
+	if ((fp = fopen(TNZONECFG_PATH, "r")) == NULL) {
+		zerror(zlogp, B_TRUE, "%s", TNZONECFG_PATH);
+		return (NULL);
+	}
+
+	while (fgets(line, sizeof (line), fp) != NULL) {
+		/*
+		 * Check for malformed database
+		 */
+		if (strlen(line) == MAXTNZLEN - 1)
+			break;
+		if ((zcent = tsol_sgetzcent(line, NULL, NULL)) == NULL)
+			continue;
+		if (strcmp(zcent->zc_name, zone_name) == 0)
+			break;
+		tsol_freezcent(zcent);
+		zcent = NULL;
+	}
+	(void) fclose(fp);
+
+	if (zcent == NULL) {
+		zerror(zlogp, B_FALSE, "zone requires a label assignment. "
+		    "See tnzonecfg(4)");
+	} else {
+		if (zlabel == NULL)
+			zlabel = m_label_alloc(MAC_LABEL);
+		/*
+		 * Save this zone's privileges for later read-down processing
+		 */
+		if ((zprivs = priv_allocset()) == NULL) {
+			zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
+			return (NULL);
+		} else {
+			priv_copyset(privs, zprivs);
+		}
+	}
+	return (zcent);
+}
+
+/*
+ * Add the Trusted Extensions multi-level ports for this zone.
+ */
+static void
+set_mlps(zlog_t *zlogp, zoneid_t zoneid, tsol_zcent_t *zcent)
+{
+	tsol_mlp_t *mlp;
+	tsol_mlpent_t tsme;
+
+	if (!is_system_labeled())
+		return;
+
+	tsme.tsme_zoneid = zoneid;
+	tsme.tsme_flags = 0;
+	for (mlp = zcent->zc_private_mlp; !TSOL_MLP_END(mlp); mlp++) {
+		tsme.tsme_mlp = *mlp;
+		if (tnmlp(TNDB_LOAD, &tsme) != 0) {
+			zerror(zlogp, B_TRUE, "cannot set zone-specific MLP "
+			    "on %d-%d/%d", mlp->mlp_port,
+			    mlp->mlp_port_upper, mlp->mlp_ipp);
+		}
+	}
+
+	tsme.tsme_flags = TSOL_MEF_SHARED;
+	for (mlp = zcent->zc_shared_mlp; !TSOL_MLP_END(mlp); mlp++) {
+		tsme.tsme_mlp = *mlp;
+		if (tnmlp(TNDB_LOAD, &tsme) != 0) {
+			zerror(zlogp, B_TRUE, "cannot set shared MLP "
+			    "on %d-%d/%d", mlp->mlp_port,
+			    mlp->mlp_port_upper, mlp->mlp_ipp);
+		}
+	}
+}
+
+static void
+remove_mlps(zlog_t *zlogp, zoneid_t zoneid)
+{
+	tsol_mlpent_t tsme;
+
+	if (!is_system_labeled())
+		return;
+
+	(void) memset(&tsme, 0, sizeof (tsme));
+	tsme.tsme_zoneid = zoneid;
+	if (tnmlp(TNDB_FLUSH, &tsme) != 0)
+		zerror(zlogp, B_TRUE, "cannot flush MLPs");
+}
+
 int
 prtmount(const char *fs, void *x) {
 	zerror((zlog_t *)x, B_FALSE, "  %s", fs);
@@ -2816,6 +3373,9 @@
 	int xerr;
 	char *kzone;
 	FILE *fp = NULL;
+	tsol_zcent_t *zcent = NULL;
+	int match = 0;
+	int doi = 0;
 
 	if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
 		zerror(zlogp, B_TRUE, "unable to determine zone root");
@@ -2842,6 +3402,17 @@
 		goto error;
 	}
 
+	if (is_system_labeled()) {
+		zcent = get_zone_label(zlogp, privs);
+		if (zcent) {
+			match = zcent->zc_match;
+			doi = zcent->zc_doi;
+			*zlabel = zcent->zc_label;
+		} else {
+			goto error;
+		}
+	}
+
 	kzone = zone_name;
 
 	/*
@@ -2911,7 +3482,7 @@
 
 	xerr = 0;
 	if ((zoneid = zone_create(kzone, rootpath, privs, rctlbuf,
-	    rctlbufsz, zfsbuf, zfsbufsz, &xerr)) == -1) {
+	    rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel)) == -1) {
 		if (xerr == ZE_AREMOUNTS) {
 			if (zonecfg_find_mounts(rootpath, NULL, NULL) < 1) {
 				zerror(zlogp, B_FALSE,
@@ -2949,6 +3520,7 @@
 	if (!mount_cmd && bind_to_pool(zlogp, zoneid) != 0)
 		zerror(zlogp, B_FALSE, "WARNING: unable to bind zone to "
 		    "requested pool; using default pool.");
+	set_mlps(zlogp, zoneid, zcent);
 	rval = zoneid;
 	zoneid = -1;
 
@@ -2961,6 +3533,8 @@
 	if (fp != NULL)
 		zonecfg_close_scratch(fp);
 	lofs_discard_mnttab();
+	if (zcent != NULL)
+		tsol_freezcent(zcent);
 	return (rval);
 }
 
@@ -3109,6 +3683,8 @@
 		goto error;
 	}
 
+	remove_mlps(zlogp, zoneid);
+
 	if (zone_destroy(zoneid) != 0) {
 		zerror(zlogp, B_TRUE, "unable to destroy zone");
 		goto error;
--- a/usr/src/common/ipf/ip_compat.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/common/ipf/ip_compat.h	Fri Mar 24 12:29:20 2006 -0800
@@ -1,9 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
 /*
  * Copyright (C) 1999-2001, 2003 by Darren Reed.
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1305,6 +1325,7 @@
 #undef	IPOPT_LSRR
 #define	IPOPT_LSRR	131
 #define	IPOPT_E_SEC	133	/* E-SEC */
+#undef	IPOPT_CIPSO
 #define	IPOPT_CIPSO	134	/* CIPSO */
 #undef	IPOPT_SATID
 #define	IPOPT_SATID	136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/tsol/blabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,383 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	bl.c - Binary label operations for kernel and user.
+ *
+ *		These routines initialize, compare, set and extract portions
+ *	of binary labels.
+ */
+
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
+
+/*
+ *	bltype - Check the type of a label structure.
+ *
+ *	Entry	label = Address of the label to check.
+ *		type = Label type to check:
+ *			SUN_SL_ID = Sensitivity Label,
+ *			SUN_SL_UN = Undefined Sensitivity Label structure,
+ *			SUN_IL_ID = Information Label,
+ *			SUN_IL_UN = Undefined Information Label structure,
+ *			SUN_CLR_ID = Clearance, or
+ *			SUN_CLR_UN = Undefined Clearance structure.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if the label is the type requested,
+ *			otherwise false.
+ *
+ *	Calls	BLTYPE.
+ */
+
+int
+bltype(const void *label, uint8_t type)
+{
+
+	return (BLTYPE(label, type));
+}
+
+
+/*
+ *	blequal - Compare two labels for Classification and Compartments set
+ *			equality.
+ *
+ *	Entry	label1, label2 = label levels to compare.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if labels equal,
+ *			otherwise false.
+ *
+ *	Calls	BLEQUAL.
+ */
+
+int
+blequal(const m_label_t *label1, const m_label_t *label2)
+{
+
+	return (BLEQUAL(label1, label2));
+}
+
+
+/*
+ *	bldominates - Compare two labels for Classification and Compartments
+ *			sets dominance.
+ *
+ *	Entry	label1, label2 = labels levels to compare.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if label1 dominates label2,
+ *			otherwise false.
+ *
+ *	Calls	BLDOMINATES.
+ */
+
+int
+bldominates(const m_label_t *label1, const m_label_t *label2)
+{
+
+	return (BLDOMINATES(label1, label2));
+}
+
+
+/*
+ *	blstrictdom - Compare two labels for Classification and Compartments
+ *			sets strict dominance.
+ *
+ *	Entry	label1, label2 = labels levels to compare.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if label1 dominates and is not equal to label2,
+ *			otherwise false.
+ *
+ *	Calls	BLSTRICTDOM.
+ */
+
+int
+blstrictdom(const m_label_t *label1, const m_label_t *label2)
+{
+
+	return (BLSTRICTDOM(label1, label2));
+}
+
+
+/*
+ *	blinrange - Compare a label's classification and compartments set to
+ *		    be within a lower and upper bound (range).
+ *
+ *	Entry	label = label level to compare.
+ *		range = level range to compare against.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if label is within the range,
+ *			otherwise false.
+ *
+ *	Calls BLINRANGE.
+ */
+
+int
+blinrange(const m_label_t *label, const m_range_t *range)
+{
+	return (BLDOMINATES((label), ((range)->lower_bound)) &&
+	    BLDOMINATES(((range)->upper_bound), (label)));
+}
+
+/*
+ * This is the TS8 version which is used in the kernel
+ */
+
+int
+_blinrange(const m_label_t *label, const brange_t *range)
+{
+	return (BLINRANGE(label, range));
+}
+
+#ifdef _KERNEL
+/*
+ *	blinlset - Check if the label belongs to the set
+ *
+ *	Entry	label = label level to compare.
+ *		lset = label set to compare against.
+ *
+ *	Exit	None.
+ *
+ *	Returns	True if label is an element of the set,
+ *			otherwise false.
+ *
+ */
+
+int
+blinlset(const m_label_t *label, const blset_t lset)
+{
+	int i;
+
+	for (i = 0; i < NSLS_MAX; i++)
+		if (BLEQUAL(label, &lset[i]))
+			return (B_TRUE);
+	return (B_FALSE);
+}
+#endif /* _KERNEL */
+
+
+/*
+ *	blmaximum - Least Upper Bound of two levels.
+ *
+ *	Entry	label1, label2 = levels to bound.
+ *
+ *	Exit	label1 replaced by the LUB of label1 and label2.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BLMAXIMUM.
+ */
+
+void
+blmaximum(m_label_t *label1, const m_label_t *label2)
+{
+
+	BLMAXIMUM(label1, label2);
+}
+
+
+/*
+ *	blminimum - Greatest Lower Bound of two levels.
+ *
+ *	Entry	label1, label2 = levels to bound.
+ *
+ *	Exit	label1 replaced by the GLB of label1 and label2.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BLMINIMUM.
+ */
+
+void
+blminimum(m_label_t *label1, const m_label_t *label2)
+{
+
+	BLMINIMUM(label1, label2);
+}
+
+
+/*
+ *	bsllow - Initialize an admin_low Sensitivity Label.
+ *
+ *	Entry	label = Sensitivity Label structure to be initialized.
+ *
+ *	Exit	label = Initialized to the admin_low Sensitivity Label.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BSLLOW.
+ */
+
+void
+bsllow(bslabel_t *label)
+{
+
+	BSLLOW(label);
+}
+
+
+/*
+ *	bslhigh - Initialize an admin_high Sensitivity Label.
+ *
+ *	Entry	label = Sensitivity Label structure to be initialized.
+ *
+ *	Exit	label = Initialized to the admin_high Sensitivity Label.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BSLHIGH.
+ */
+
+void
+bslhigh(bslabel_t *label)
+{
+
+	BSLHIGH(label);
+}
+
+/*
+ *	bclearlow - Initialize an admin_low Clearance.
+ *
+ *	Entry	clearance = Clearnace structure to be initialized.
+ *
+ *	Exit	clearance = Initialized to the admin_low Clearance.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BCLEARLOW.
+ */
+
+void
+bclearlow(bclear_t *clearance)
+{
+
+	BCLEARLOW(clearance);
+}
+
+
+/*
+ *	bclearhigh - Initialize an admin_high Clearance.
+ *
+ *	Entry	clearance = Clearance structure to be initialized.
+ *
+ *	Exit	clearance = Initialized to the admin_high Clearance.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BCLEARHIGH.
+ */
+
+void
+bclearhigh(bclear_t *clearance)
+{
+
+	BCLEARHIGH(clearance);
+}
+
+/*
+ *	bslundef - Initialize an undefined Sensitivity Label.
+ *
+ *	Entry	label = Sensitivity Label structure to be initialized.
+ *
+ *	Exit	label = Initialized to undefined Sensitivity Label.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BSLUNDEF.
+ */
+
+void
+bslundef(bslabel_t *label)
+{
+
+	BSLUNDEF(label);
+}
+
+
+/*
+ *	bclearundef - Initialize an undefined Clearance.
+ *
+ *	Entry	clearance = Clearance structure to be initialized.
+ *
+ *	Exit	clearance = Initialized to undefined Clearance.
+ *
+ *	Returns	None.
+ *
+ *	Calls	BCLEARUNDEF.
+ */
+
+void
+bclearundef(bclear_t *clearance)
+{
+
+	BCLEARUNDEF(clearance);
+}
+
+
+/*
+ *	setbltype - Set the type of a label structure.
+ *
+ *	Entry	label = Address of the label to set.
+ *		type = Label type to set:
+ *			SUN_SL_ID = Sensitivity Label,
+ *			SUN_SL_UN = Undefined Sensitivity Label structure,
+ *			SUN_IL_ID = Information Label,
+ *			SUN_IL_UN = Undefined Information Label structure,
+ *			SUN_CLR_ID = Clearance, or
+ *			SUN_CLR_UN = Undefined Clearance structure.
+ *
+ *	Exit	label = Type set to specified type.
+ *
+ *	Returns	None.
+ *
+ *	Calls	SETBLTYPE.
+ */
+
+void
+setbltype(void *label, uint8_t type)
+{
+
+	SETBLTYPE(label, type);
+}
+
+/*
+ * Returns B_TRUE if the label is invalid (initialized to all zeros).
+ */
+boolean_t
+bisinvalid(const void *label)
+{
+	return (GETBLTYPE(label) == SUN_INVALID_ID);
+}
--- a/usr/src/head/auth_list.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/auth_list.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * This is an internal header file. Not to be shipped.
@@ -50,6 +49,27 @@
 #define	WIFI_CONFIG_AUTH	"solaris.network.wifi.config"
 #define	WIFI_WEP_AUTH		"solaris.network.wifi.wep"
 
+/*
+ * Authorizations used by Trusted Solaris.
+ */
+#define	BYPASS_FILE_VIEW_AUTH	"solaris.label.win.noview"
+#define	DEVICE_CONFIG_AUTH	"solaris.device.config"
+#define	FILE_CHOWN_AUTH		"solaris.file.chown"
+#define	FILE_DOWNGRADE_SL_AUTH	"solaris.label.file.downgrade"
+#define	FILE_OWNER_AUTH		"solaris.file.owner"
+#define	FILE_UPGRADE_SL_AUTH	"solaris.label.file.upgrade"
+#define	PRINT_ADMIN_AUTH	"solaris.print.admin"
+#define	PRINT_CANCEL_AUTH	"solaris.print.cancel"
+#define	PRINT_LIST_AUTH		"solaris.print.list"
+#define	PRINT_MAC_AUTH		"solaris.label.print"
+#define	PRINT_NOBANNER_AUTH	"solaris.print.nobanner"
+#define	PRINT_POSTSCRIPT_AUTH	"solaris.print.ps"
+#define	PRINT_UNLABELED_AUTH	"solaris.print.unlabeled"
+#define	SHUTDOWN_AUTH		"solaris.system.shutdown"
+#define	SYS_ACCRED_SET_AUTH	"solaris.label.range"
+#define	WIN_DOWNGRADE_SL_AUTH	"solaris.label.win.downgrade"
+#define	WIN_UPGRADE_SL_AUTH	"solaris.label.win.upgrade"
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/head/nss_dbdefs.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/nss_dbdefs.h	Fri Mar 24 12:29:20 2006 -0800
@@ -22,7 +22,7 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
- * Database-speficic definitions for the getXXXbyYYY routines
+ * Database-specific definitions for the getXXXbyYYY routines
  * (e.g getpwuid_r(), ether_ntohost()) that use the name-service switch.
  * Database-independent definitions are in <nss_common.h>
  *
@@ -80,6 +80,10 @@
 #define	NSS_DBNAM_PROFATTR	"prof_attr"
 #define	NSS_DBNAM_USERATTR	"user_attr"
 
+#define	NSS_DBNAM_TSOL_TP	"tnrhtp"
+#define	NSS_DBNAM_TSOL_RH	"tnrhdb"
+#define	NSS_DBNAM_TSOL_ZC	"tnzonecfg"
+
 /* getspnam() et al use the "passwd" config entry but the "shadow" backend */
 #define	NSS_DBNAM_SHADOW	"shadow"
 
@@ -97,6 +101,7 @@
 #define	NSS_FILES_NS		"files nis"
 #define	NSS_NS_FALLBACK		"nis [NOTFOUND=return] files"
 #define	NSS_NS_ONLY		"nis"
+#define	NSS_TSOL_FALLBACK	"files ldap"
 
 #define	NSS_DEFCONF_ALIASES	NSS_FILES_NS
 #define	NSS_DEFCONF_AUTOMOUNT	NSS_FILES_NS
@@ -127,6 +132,10 @@
 #define	NSS_DEFCONF_PROFATTR	NSS_DEFCONF_ATTRDB
 #define	NSS_DEFCONF_EXECATTR	NSS_DEFCONF_PROFATTR
 
+#define	NSS_DEFCONF_TSOL_TP	NSS_TSOL_FALLBACK
+#define	NSS_DEFCONF_TSOL_RH	NSS_TSOL_FALLBACK
+#define	NSS_DEFCONF_TSOL_ZC	NSS_TSOL_FALLBACK
+
 /*
  * Line-lengths that the "files" and "compat" backends will try to support.
  * It may be reasonable (even advisable) to use smaller values than these.
@@ -160,6 +169,12 @@
 
 #define	NSS_MMAPLEN_EXECATTR	NSS_LINELEN_EXECATTR * 8
 
+#define	NSS_LINELEN_TSOL	NSS_BUFSIZ
+
+#define	NSS_LINELEN_TSOL_TP	NSS_LINELEN_TSOL
+#define	NSS_LINELEN_TSOL_RH	NSS_LINELEN_TSOL
+#define	NSS_LINELEN_TSOL_ZC	NSS_LINELEN_TSOL
+
 /*
  * Reasonable defaults for 'buflen' values passed to _r functions.  The BSD
  * and SunOS 4.x implementations of the getXXXbyYYY() functions used hard-
@@ -193,6 +208,11 @@
 #define	NSS_BUFLEN_PROFATTR	NSS_BUFLEN_ATTRDB
 #define	NSS_BUFLEN_USERATTR	((NSS_BUFLEN_ATTRDB) * 8)
 
+#define	NSS_BUFLEN_TSOL		NSS_LINELEN_TSOL
+
+#define	NSS_BUFLEN_TSOL_TP	NSS_BUFLEN_TSOL
+#define	NSS_BUFLEN_TSOL_RH	NSS_BUFLEN_TSOL
+#define	NSS_BUFLEN_TSOL_ZC	NSS_BUFLEN_TSOL
 
 /*
  * Arguments and results, passed between the frontends and backends for
@@ -553,6 +573,10 @@
 #define	NSS_DBOP_PROFATTR_BYNAME	NSS_DBOP_ATTRDB_BYNAME
 #define	NSS_DBOP_USERATTR_BYNAME	NSS_DBOP_ATTRDB_BYNAME
 
+#define	NSS_DBOP_TSOL_TP_BYNAME		(NSS_DBOP_next_iter)
+#define	NSS_DBOP_TSOL_RH_BYADDR		(NSS_DBOP_next_iter)
+#define	NSS_DBOP_TSOL_ZC_BYNAME		(NSS_DBOP_next_iter)
+
 /*
  * Used all over in the switch code. The best home for it I can think of.
  * Power-of-two alignments only.
--- a/usr/src/head/protocols/routed.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/protocols/routed.h	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -108,6 +108,18 @@
 	} au;
 };
 
+struct rip_emetric {
+	uint16_t	rip_metric;
+	uint16_t	rip_mask;
+	uint32_t	rip_token[1];
+};
+
+struct rip_sec_entry {
+	uint32_t	rip_dst;
+	uint32_t	rip_count;
+	struct rip_emetric rip_emetric[1];
+};
+
 struct rip {
 	uint8_t    rip_cmd;		/* request/response */
 	uint8_t    rip_vers;		/* protocol version # */
@@ -116,10 +128,15 @@
 	    struct netinfo ru_nets[1];	/* variable length... */
 	    char    ru_tracefile[1];	/* ditto ... */
 	    struct netauth ru_auth[1];
+	    struct {
+		uint32_t rip_generation;
+		struct rip_sec_entry rip_sec_entry[1];
+	    } ru_tsol;
 	} ripun;
 #define	rip_nets	ripun.ru_nets
 #define	rip_tracefile	ripun.ru_tracefile
 #define	rip_auths	ripun.ru_auth
+#define	rip_tsol	ripun.ru_tsol
 };
 
 struct entryinfo {
@@ -149,6 +166,9 @@
 #define	RIPCMD_POLL		5	/* like request, but anyone answers */
 #define	RIPCMD_POLLENTRY	6	/* like poll, but for entire entry */
 
+#define	RIPCMD_SEC_RESPONSE	51	/* response includes E-metrics */
+#define	RIPCMD_SEC_T_RESPONSE	52	/* tunneling */
+
 #define	RIPCMD_MAX		7
 
 #define	HOPCNT_INFINITY		16	/* per Xerox NS */
--- a/usr/src/head/tar.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/tar.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,10 +18,13 @@
  *
  * CDDL HEADER END
  */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 /*	Copyright (c) 1988 AT&T	*/
 /*	  All Rights Reserved  	*/
 
-
 #ifndef _TAR_H
 #define	_TAR_H
 
@@ -68,6 +70,25 @@
 #define	TOWRITE		00002
 #define	TOEXEC		00001
 
+/*
+ *      Types used in ancillary files
+ */
+#define	ACL_HDR		'A'	/* Access Control List */
+#define	LBL_TYPE	'L'	/* Trusted Extensions file label */
+#define	DIR_TYPE	'D'	/* Trusted Extensions directory label */
+/*
+ * Attribute types used in Trusted Solaris ancillary files
+ * that are interpreted for backward compatibility
+ */
+#define	SLD_TYPE	'S'	/* single-level directory component */
+#define	PATH_TYPE	'P'	/* Path component */
+#define	MLD_TYPE	'M'	/* multi-level directory component */
+#define	FILE_TYPE	'F'	/* Have to handle files differently */
+#define	APRIV_TYPE	'P'	/* allowed privileges data type in file */
+#define	FPRIV_TYPE	'p'	/* forced privileges data type in file */
+#define	COMP_TYPE	'C'	/* path components, use for MLD */
+#define	ATTR_FLAG_TYPE	'F'	/* file attribute flag bytes data type */
+#define	LK_COMP_TYPE	'K'	/* link data path component */
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/head/ucred.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/ucred.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,6 +30,7 @@
 
 #include <sys/types.h>
 #include <sys/priv.h>
+#include <sys/tsol/label.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -66,6 +66,8 @@
 
 extern zoneid_t ucred_getzoneid(const ucred_t *);
 
+extern bslabel_t *ucred_getlabel(const ucred_t *);
+
 extern projid_t ucred_getprojid(const ucred_t *);
 
 #else	/* Non ANSI */
@@ -93,6 +95,8 @@
 
 extern zoneid_t ucred_getzoneid(/* ucred_t * */);
 
+extern bslabel_t *ucred_getlabel(/* const ucred_t * */);
+
 extern projid_t ucred_getprojid(/* ucred_t * */);
 
 #endif	/* __STDC__ */
--- a/usr/src/head/user_attr.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/user_attr.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -93,6 +92,21 @@
 #define	USERATTR_LIMPRIV_KW		"limitpriv"
 #define	USERATTR_DFLTPRIV_KW		"defaultpriv"
 #define	USERATTR_LOCK_AFTER_RETRIES_KW	"lock_after_retries"
+#define	USERATTR_CLEARANCE		"clearance"
+#define	USERATTR_LABELVIEW		"labelview"
+#define	USERATTR_LABELVIEW_EXTERNAL	"external"
+#define	USERATTR_LABELVIEW_HIDESL	"hidesl"
+#define	USERATTR_HIDESL			USERATTR_LABELVIEW_HIDESL
+#define	USERATTR_LABELVIEW_INTERNAL	"internal"
+#define	USERATTR_LABELVIEW_SHOWSL	"showsl"
+#define	USERATTR_LABELTRANS		"labeltrans"
+#define	USERATTR_LOCK_NO		"no"
+#define	USERATTR_LOCK_YES		"yes"
+#define	USERATTR_MINLABEL		"min_label"
+#define	USERATTR_PASSWD			"password"
+#define	USERATTR_PASSWD_AUTOMATIC	"automatic"
+#define	USERATTR_PASSWD_MANUAL		"manual"
+#define	USERATTR_TYPE_ROLE		USERATTR_TYPE_NONADMIN_KW
 
 
 /*
--- a/usr/src/head/zone.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/head/zone.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/zone.h>
 #include <sys/priv.h>
+#include <tsol/label.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -57,7 +57,8 @@
 
 /* System call API */
 extern zoneid_t	zone_create(const char *, const char *,
-    const struct priv_set *, const char *, size_t, const char *, size_t, int *);
+    const struct priv_set *, const char *, size_t, const char *, size_t, int *,
+    int, int, const bslabel_t *);
 extern int	zone_boot(zoneid_t, const char *);
 extern int	zone_destroy(zoneid_t);
 extern ssize_t	zone_getattr(zoneid_t, int, void *, size_t);
--- a/usr/src/lib/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -184,6 +184,8 @@
 	libxnet		\
 	libzonecfg	\
 	libzoneinfo	\
+	libtsnet	\
+	libtsol		\
 	gss_mechs/mech_spnego	\
 	gss_mechs/mech_dummy	\
 	gss_mechs/mech_dh	\
@@ -268,6 +270,7 @@
 	libsldap	\
 	libslp		\
 	libsmedia	\
+	libtsol		\
 	libuutil	\
 	libwanboot	\
 	libwanbootutil	\
@@ -327,6 +330,7 @@
 	libmail		\
 	libmtmalloc	\
 	libnvpair	\
+	libnsl		\
 	libpam		\
 	libpctx		\
 	libpicl		\
@@ -349,6 +353,8 @@
 	libtnf		\
 	libtnfctl	\
 	libtnfprobe	\
+	libtsnet	\
+	libtsol		\
 	libvolmgt	\
 	libumem		\
 	libuutil	\
@@ -425,6 +431,7 @@
 gss_mechs/mech_krb5:	libgss libnsl libsocket libresolv pkcs11
 libadt_jni:	libbsm
 $(CLOSED_BUILD)libc:		$(CLOSED)/lib/libc_i18n
+libbsm:		libtsol
 libcmdutils:	libavl
 libcontract:	libnvpair
 libdevid:	libdevinfo
@@ -450,9 +457,10 @@
 libsctp:	libsocket
 libsocket:	libnsl
 libldap5:	libsasl libsocket libnsl libmd5
-libsldap:	libldap5
+libsldap:	libldap5 libtsol
 libpool:	libnvpair libexacct
 libproject:	libpool libproc libsecdb
+libtsnet:	libnsl libtsol libsecdb
 libwrap:	libnsl libsocket
 libwanboot:	libnvpair libresolv libnsl libsocket libdevinfo libinetutil \
 		libdhcputil openssl
--- a/usr/src/lib/auditd_plugins/syslog/systoken.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/auditd_plugins/syslog/systoken.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,6 +45,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include <bsm/libbsm.h>
+#include <sys/tsol/label.h>
 #include "toktable.h"	/* ../praudit */
 #include "sysplugin.h"
 #include "systoken.h"
@@ -1381,46 +1381,6 @@
 
 	return (0);
 }
-/*
- * Format of clearance token:
- *	clearance		adr_char*(sizeof (bclear_t))
- *
- * ifdef TSOL because of bclear_t
- */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
-int
-clearance_token(parse_context_t *ctx)
-{
-#ifdef	TSOL
-
-	ctx->adr.adr_now += sizeof (bclear_t);
-
-	return (0);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
-}
-/*
- * Format of ilabel token:
- *	ilabel			adr_char*(sizeof (bilabel_t))
- */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
-int
-ilabel_token(parse_context_t *ctx)
-{
-#ifdef	TSOL
-
-	ctx->adr.adr_now += sizeof (bilabel_t);
-
-	return (0);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
-}
 
 /*
  * -----------------------------------------------------------------------
@@ -1445,22 +1405,23 @@
 
 /*
  * Format of slabel token:
- *	slabel			adr_char*(sizeof (bslabel_t))
+ *	label ID                1 byte
+ *	compartment length      1 byte
+ *	classification          2 bytes
+ *	compartment words       <compartment length> * 4 bytes
  */
-#ifndef	TSOL
-/* ARGSUSED */
-#endif	/* !TSOL */
 int
 slabel_token(parse_context_t *ctx)
 {
-#ifdef	TSOL
+	char	c;
 
-	ctx->adr.adr_now += sizeof (bslabel_t);
+	ctx->adr.adr_now += sizeof (char);	/* label ID */
+	adrm_char(&(ctx->adr), &c, 1);
+
+	ctx->adr.adr_now += sizeof (ushort_t);	/* classification */
+	ctx->adr.adr_now += 4 * c;		/* compartments */
 
 	return (0);
-#else	/* !TSOL */
-	return (-1);
-#endif	/* TSOL */
 }
 
 /*
--- a/usr/src/lib/auditd_plugins/syslog/systoken.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/auditd_plugins/syslog/systoken.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -97,9 +96,7 @@
 extern void	attribute_token(adr_t *, parse_context_t *);
 extern void	s5_IPC_perm_token(adr_t *, parse_context_t *);
 extern void	group_token();
-extern void	ilabel_token(adr_t *, parse_context_t *);
 extern void	slabel_token(adr_t *, parse_context_t *);
-extern void	clearance_token(adr_t *, parse_context_t *);
 extern void	privilege_token(adr_t *, parse_context_t *);
 extern void	useofpriv_token(adr_t *, parse_context_t *);
 extern void	zonename_token(adr_t *, parse_context_t *);
--- a/usr/src/lib/common/inc/c_synonyms.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/common/inc/c_synonyms.h	Fri Mar 24 12:29:20 2006 -0800
@@ -414,6 +414,7 @@
 #define	isastream			_isastream
 #define	isatty				_isatty
 #define	issetugid			_issetugid
+#define	is_system_labeled		_is_system_labeled
 #define	jrand48				_jrand48
 #define	kaio				_kaio
 #define	kill				_kill
--- a/usr/src/lib/libbsm/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -27,7 +28,6 @@
 # lib/libbsm/Makefile
 #
 
-include ../../Makefile.master
 include ../Makefile.lib
 
 SUBDIRS=	spec .WAIT $(MACH) $(BUILD64) $(MACH64)
@@ -46,54 +46,13 @@
 
 all clean clobber delete install lint package: $(SUBDIRS)
 
-OBJECTS=	adr.o \
-		adrf.o \
-		adrm.o \
-		adt.o \
-		adt_token.o \
-		adt_xlate.o \
-		au_open.o \
-		au_preselect.o \
-		au_to.o \
-		au_usermask.o \
-		audit_allocate.o \
-		audit_class.o \
-		audit_cron.o \
-		audit_crontab.o \
-		audit_at.o \
-		audit_event.o \
-		audit_ftpd.o \
-		audit_halt.o \
-		audit_inetd.o \
-		audit_kadmind.o \
-		audit_krb5kdc.o \
-		audit_mountd.o \
-		audit_newgrp.o \
-		audit_plugin.o \
-		audit_reboot.o \
-		audit_rexd.o \
-		audit_rexecd.o \
-		audit_rshd.o \
-		audit_settid.o \
-		audit_shutdown.o \
-		audit_uadmin.o \
-		audit_user.o \
-		bsm.o \
-		generic.o \
-		getacinfo.o \
-		getacval.o \
-		getauditflags.o \
-		getdaent.o \
-		getdment.o \
-		getfaudflgs.o
-
 COMMONDIR = common
 
 #
 # Macros for libbsm header files. These define user-level only interfaces.
 #
 GENHDRS = audit_uevents.h
-HDRS = libbsm.h devices.h adt.h adt_event.h audit_private.h
+HDRS = libbsm.h devices.h devalloc.h adt.h adt_event.h audit_private.h
 COMMONHDRS =	$(HDRS:%=$(COMMONDIR)/%)
 ROOTHDRDIR = 	$(ROOT)/usr/include/bsm
 ROOTCHDRS = 	$(HDRS:%=$(ROOTHDRDIR)/%)
@@ -154,10 +113,8 @@
 #
 # message catalogue file
 #
-TEXT_DOMAIN= SUNW_OST_OSLIB
-POFILE= libbsm.po
-CATALOG=libbsm.po
-POFILES= $(OBJECTS:%.o=%.po)
+MSGFILES =	`$(GREP) -l gettext $(COMMONDIR)/*.c`
+POFILE =	libbsm.po
 
 #
 # Definitions for XML (DTD AND XSL)
@@ -241,24 +198,9 @@
 $(ROOTETCSECURITY)/%: %.txt
 	$(INS.rename)
 
-%.po: $(COMMONDIR)/%.c
-	$(COMPILE.cpp) $<  > $<.i
-	$(BUILD.po)
-
-_msg: $(MSGDOMAIN) $(POFILE)
-	$(RM) $(MSGDOMAIN)/$(CATALOG)
-	$(CP) $(POFILE) $(MSGDOMAIN)
+$(POFILE):	 pofile_MSGFILES
 
-catalog: _msg
-
-po_clean:
-	$(RM) $(POFILES) $(POFILE)
-
-clobber: po_clean
-
-$(POFILE): .WAIT $(POFILES)
-	$(RM) $@
-	$(CAT) $(POFILES) > $@
+_msg:	$(MSGDOMAINPOFILE)
 
 # has strings but doesn't use gettext
 adt_xlate.po: $(COMMONDIR)/adt_xlate.c
@@ -267,11 +209,10 @@
 	$(SED) "/^domain/d" < messages.po > adt_xlate.po
 	$(RM) messages.po
 
-$(MSGDOMAIN):
-	$(INS.dir)
-
-
 spec $(MACH) $(MACH64) :	FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
 FRC:
+
+include ../Makefile.targ
+include ../../Makefile.msg.targ
--- a/usr/src/lib/libbsm/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -24,7 +24,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# lib/libbsm/Makefile
+# lib/libbsm/Makefile.com
 #
 
 LIBRARY =	libbsm.a
@@ -67,7 +67,10 @@
 		getacval.o \
 		getauditflags.o \
 		getdaent.o \
+		getdevicerange.o \
 		getdment.o \
+		getdadefs.o \
+		devalloc.o \
 		getfaudflgs.o
 
 #
@@ -94,7 +97,10 @@
 
 CFLAGS	+=	$(CCVERBOSE)
 DYNFLAGS +=	-M$(MAPFILE)
-LDLIBS +=	-lsocket -lnsl -lmd5 -lc -lsecdb
+
+LAZYLIBS =	$(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+LDLIBS +=	-lsocket -lnsl -lmd5 -lc -lsecdb $(LAZYLIBS)
+lint :=		LAZYLIBS = -ltsol
 
 COMDIR=		../common
 
--- a/usr/src/lib/libbsm/audit_class.txt	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/audit_class.txt	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,12 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -62,6 +61,29 @@
 0x00100000:ps:process start/stop
 0x00200000:pm:process modify
 0x00300000:pc:process (meta-class)
+#
+# The following four masks define X server related audit classes which
+# are applicable to Trusted Extensions.  X server audit events are mapped
+# to these classes per the following criteria:
+#
+# xp :	Protocols audited for use of privilege (successful or otherwise).
+#	E.g., ChangeWindowAttributes is audited when issued by a client to
+#	change attributes of another client's window.  This class also includes
+#	any administrative protocols (e.g. SetAccessControl).
+# xc :	Server objects creation/destruction; e.g., CreateWindow.
+# xs :	Protocols that do not return X error messages to clients on failure for
+#	lack for security attributes.  E.g., GetImage does not return BadWindow 
+#	error if it cannot read from a window for lack of privilege. It just
+#	does not read from that window.
+#	These events should be selected for audit on success only. Selecting
+#	them for failure will cause a lot of noise in the audit trail.
+# xx : All above X classes.
+#
+0x00400000:xp:X - privileged/administrative operations
+0x00800000:xc:X - object create/destroy
+0x01000000:xs:X - operations that always silently fail, if bad
+0x01c00000:xx:X - all X events (meta-class)
+#
 0x20000000:io:ioctl
 0x40000000:ex:exec
 0x80000000:ot:other
--- a/usr/src/lib/libbsm/audit_event.txt	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/audit_event.txt	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,13 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -48,10 +48,25 @@
 #  2048 - 32767	Reserved for the Solaris TCB programs.
 # 32768 - 65535	Available for third party TCB applications.
 #
-# 6144 - 32767  SunOS 5.X user level audit events
+#
+# Allocation of reserved kernel events:
+# (NOTE: the kernel event table, and possibly MAX_KEVENTS, must be updated
+# in audit_kevents.h when changes are made to kernel events.)
+#	    1 -   511	allocated for Solaris
+#	  512 -  1023	allocated for Trusted Solaris/Trusted Extensions
+#	 1024 -  2047	(reserved but not allocated)
+#
+# Allocation of user level audit events:
+#	 2048 -  5999	(reserved but not allocated)
+#	 6000 -  7999	allocated for Solaris
+#	 8000 -  8999	(reserved but not allocated)
+#	 9000 -  9999	allocated for Trusted Solaris/Trusted Extensions
+#	10000 - 32767	(reserved but not allocated)
+#	32768 - 65535	(Available for third party TCB applications)
 #
 #
 # kernel audit events
+#	    1 -   511	allocated for Solaris
 #
 0:AUE_NULL:indir system call:no
 1:AUE_EXIT:exit(2):ps
@@ -173,8 +188,6 @@
 113:AUE_SYSTEMBOOT:system booted:na
 114:AUE_ASYNC_DAEMON_EXIT:async_daemon(2) exited:no
 115:AUE_NFSSVC_EXIT:nfssvc(2) exited:no
-128:AUE_WRITEL:writel(2):no
-129:AUE_WRITEVL:writevl(2):no
 130:AUE_GETAUID:getauid(2):aa
 131:AUE_SETAUID:setauid(2):aa
 132:AUE_GETAUDIT:getaudit(2):aa
@@ -328,7 +341,12 @@
 292:AUE_CRYPTOADM:kernel cryptographic framework:as
 293:AUE_CONFIGSSL:configure kernel SSL:as
 #
+# Trusted Solaris/Trusted Extensions kernel audit events
+#	  512 -  1023	allocated for Trusted Solaris/Trusted Extensions
+#
+#
 # user level audit events
+#	6000 -  7999	allocated for Solaris
 #
 # 2048 - 6143	Reserved
 #
@@ -409,3 +427,113 @@
 6225:AUE_inetd_failrate:inetd failrate:na
 6226:AUE_inetd_ratelimit:inetd ratelimit:na
 6227:AUE_zlogin:login - zlogin:lo
+#
+# Trusted Solaris/Trusted Extensions user level audit events
+#	9000 -  9999	allocated for Trusted Solaris/Trusted Extensions
+#
+9035:AUE_sl_change:Workspace label change:ap
+9037:AUE_file_copy:file copy:fm
+9038:AUE_file_move:file move:fm
+9039:AUE_sel_mgr_xfer:selection manager transfer:fm
+9101:AUE_ClientConnect:client connection to x server:lo
+9102:AUE_ClientDisconnect:client disconn. from x server:lo
+9120:AUE_ChangeProperty:XChangeProperty(3X11):xc
+9121:AUE_DeleteProperty:XDeleteProperty(3X11):xc
+9137:AUE_GrabServer:XGrabServer(3X11):ot
+9138:AUE_UngrabServer:XUngrabServer(3X11):ot
+9146:AUE_SetFontPath:XSetFontPath(3X11):ot
+9173:AUE_InstallColormap:XInstallColormap(3X11):ot
+9174:AUE_UninstallColormap:XUninstallColormap(3X11):xp
+9193:AUE_SetScreenSaver:XSetScreenSaver(3X11):xp
+9194:AUE_ChangeHosts:XChangeHosts(3X11):ot
+9195:AUE_SetAccessControl:XSetAccessControl(3X11):xp
+9196:AUE_SetCloseDownMode:XSetCloseDownMode(3X11):xs
+9197:AUE_KillClient:XKillClient(3X11):xc
+9202:AUE_XExtensions:X server extensions:xp
+9103:AUE_CreateWindow:XCreateWindow(3X11):xc
+9104:AUE_ChangeWindowAttributes:XChangeWindowAttributes(3X11):xp
+9105:AUE_GetWindowAttributes:XGetWindowAttributes(3X11):xp
+9106:AUE_DestroyWindow:XDestroyWindow(3X11):xc
+9107:AUE_DestroySubwindows:XDestroySubwindows(3X11):xc
+9108:AUE_ChangeSaveSet:XChangeSaveSet(3X11):xp
+9109:AUE_ReparentWindow:XReparentWindow(3X11):xp
+9110:AUE_MapWindow:XMapWindow(3X11):xp
+9111:AUE_MapSubwindows:XMapSubwindows(3X11):xp
+9112:AUE_UnmapWindow:XUnmapWindow(3X11):xp
+9113:AUE_UnmapSubwindows:XUnmapSubwindows(3X11):xp
+9114:AUE_ConfigureWindow:XConfigureWindow(3X11):xp
+9115:AUE_CirculateWindow:XCirculateWindow(3X11):xp
+9116:AUE_GetGeometry:XGetGeometry(3X11):xp
+9117:AUE_QueryTree:XQueryTree(3X11):xp
+9118:AUE_InternAtom:XInternAtom(3X11):xs
+9119:AUE_GetAtomName:XGetAtomName(3X11):xs
+9122:AUE_GetProperty:XGetProperty(3X11):xp
+9123:AUE_ListProperties:XListProperties(3X11):xp
+9124:AUE_SetSelectionOwner:XSetSelectionOwner(3X11):xp
+9125:AUE_GetSelectionOwner:XGetSelectionOwner(3X11):xs
+9126:AUE_ConvertSelection:XConvertSelection(3X11):xs
+9127:AUE_SendEvent:XSendEvent(3X11):xs
+9128:AUE_GrabPointer:XGrabPointer(3X11):xs
+9129:AUE_UngrabPointer:XUngrabPointer(3X11):xs
+9130:AUE_GrabButton:XGrabButton(3X11):xp
+9131:AUE_UngrabButton:XUngrabButton(3X11):xs
+9132:AUE_ChangeActivePointerGrab:XChangeActivePointerGrab(3X11):xs
+9133:AUE_GrabKeyboard:XGrabKeyboard(3X11):xp
+9134:AUE_UngrabKeyboard:XUngrabKeyboard(3X11):xs
+9135:AUE_GrabKey:XGrabKey(3X11):xp
+9136:AUE_UngrabKey:XUngrabKey(3X11):xp
+9139:AUE_QueryPointer:XQueryPointer(3X11):xp
+9140:AUE_GetMotionEvents:XGetMotionEvents(3X11):xp
+9141:AUE_TranslateCoords:XTranslateCoords(3X11):xp
+9142:AUE_WarpPointer:XWarpPointer(3X11):xs
+9143:AUE_SetInputFocus:XSetInputFocus(3X11):xs
+9144:AUE_GetInputFocus:XGetInputFocus(3X11):xs
+9145:AUE_QueryKeymap:XQueryKeymap(3X11):xp
+9147:AUE_FreePixmap:XFreePixmap(3X11):xc
+9148:AUE_ChangeGC:XChangeGC(3X11):xp
+9149:AUE_CopyGC:XCopyGC(3X11):xp
+9150:AUE_SetDashes:XSetDashes(3X11):xp
+9151:AUE_SetClipRectangles:XSetClipRectangles(3X11):xp
+9152:AUE_FreeGC:XFreeGC(3X11):xc
+9153:AUE_ClearArea:XClearArea(3X11):xp
+9154:AUE_CopyArea:XCopyArea(3X11):xs
+9155:AUE_CopyPlane:XCopyPlane(3X11):xs
+9156:AUE_PolyPoint:XPolyPoint(3X11):xp
+9157:AUE_PolyLine:XPolyLine(3X11):xp
+9158:AUE_PolySegment:XPolySegment(3X11):xp
+9159:AUE_PolyRectangle:XPolyRectangle(3X11):xs
+9160:AUE_PolyArc:XPolyArc(3X11):xp
+9161:AUE_FillPolygon:XFillPolygon(3X11):xp
+9162:AUE_PolyFillRectangle:XPolyFillRectangle(3X11):xp
+9163:AUE_PolyFillArc:XPolyFillArc(3X11):xp
+9164:AUE_PutImage:XPutImage(3X11):xp
+9165:AUE_GetImage:XGetImage(3X11):xs
+9166:AUE_PolyText8:XPolyText8(3X11):xp
+9167:AUE_PolyText16:XPolyText16(3X11):xp
+9168:AUE_ImageText8:XImageText8(3X11):xp
+9169:AUE_ImageText16:XImageText16(3X11):xp
+9170:AUE_CreateColormap:XCreateColormap(3X11):xc
+9171:AUE_FreeColormap:XFreeColormap(3X11):xc
+9172:AUE_CopyColormapAndFree:XCopyColormapAndFree(3X11):xp
+9175:AUE_ListInstalledColormaps:XListInstalledColormaps(3X11):xs
+9176:AUE_AllocColor:XAllocColor(3X11):xc
+9177:AUE_AllocNamedColor:XAllocNamedColor(3X11):xc
+9178:AUE_AllocColorCells:XAllocColorCells(3X11):xc
+9179:AUE_AllocColorPlanes:XAllocColorPlanes(3X11):xc
+9180:AUE_FreeColors:XFreeColors(3X11):xc
+9181:AUE_StoreColors:XStoreColors(3X11):xp
+9182:AUE_StoreNamedColor:XStoreNamedColor(3X11):xp
+9183:AUE_QueryColors:XQueryColors(3X11):xp
+9184:AUE_LookupColor:XLookupColor(3X11):xp
+9185:AUE_CreateCursor:XCreateCursor(3X11):xc
+9186:AUE_CreateGlyphCursor:XCreateGlyphCursor(3X11):xc
+9187:AUE_FreeCursor:XFreeCursor(3X11):xc
+9188:AUE_RecolorCursor:XRecolorCursor(3X11):xp
+9189:AUE_ChangeKeyboardMapping:XChangeKeyboardMapping(3X11):xs
+9190:AUE_ChangeKeyboardControl:XChangeKeyboardControl(3X11):xs
+9191:AUE_Bell:XBell(3X11):xs
+9192:AUE_ChangePointerControl:XChangePointerControl(3X11):xs
+9198:AUE_RotateProperties:XRotateProperties(3X11):xp
+9199:AUE_ForceScreenSaver:XForceScreenSaver(3X11):xp
+9200:AUE_SetPointerMapping:XSetPointerMapping(3X11):xs
+9201:AUE_SetModifierMapping:XSetModifierMapping(3X11):xs
--- a/usr/src/lib/libbsm/common/adt_token.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/adt_token.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
 /*
  * adt_token.c
  *
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * This file does not provide any user callable functions.  See adt.c
@@ -41,6 +40,7 @@
 #include <sys/priv_names.h>
 #include <sys/types.h>
 #include <sys/vnode.h>
+#include <tsol/label.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -530,6 +530,9 @@
 			    au_to_newgroups(0, grouplist));
 		}
 	}
+
+	if (is_system_labeled())
+		(void) au_write(event->ae_event_handle, au_to_mylabel());
 }
 
 /*
--- a/usr/src/lib/libbsm/common/au_to.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/au_to.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,6 +41,9 @@
 #include <netinet/in.h>
 #include <netinet/in_pcb.h>
 #include <string.h>
+#include <zone.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
 
 #define	NGROUPS		16	/* XXX - temporary */
 
@@ -1242,6 +1244,50 @@
 }
 
 /*
+ * au_to_label
+ * return s:
+ *	pointer to token chain containing a sensitivity label token.
+ */
+token_t *
+au_to_label(bslabel_t *label)
+{
+	token_t *token;			/* local token */
+	adr_t adr;			/* adr memory stream header */
+	char data_header = AUT_LABEL;	/* header for this token */
+	short bs = sizeof (bslabel_t);
+
+	token = get_token(sizeof (char) + bs);
+	if (token == NULL)
+		return (NULL);
+	adr_start(&adr, token->tt_data);
+	adr_char(&adr, &data_header, 1);
+	adr_char(&adr, (char *)label, bs);
+
+	return (token);
+}
+
+/*
+ * au_to_mylabel
+ * return s:
+ *	pointer to a slabel token.
+ */
+token_t *
+au_to_mylabel(void)
+{
+	bslabel_t	slabel;
+	zoneid_t	zid = getzoneid();
+
+	if (zid == GLOBAL_ZONEID) {
+		bsllow(&slabel);
+	} else {
+		if (zone_getattr(zid, ZONE_ATTR_SLBL, &slabel,
+		    sizeof (bslabel_t)) < 0)
+			return (NULL);
+	}
+	return (au_to_label(&slabel));
+}
+
+/*
  * au_to_zonename
  * return s:
  *	pointer to a zonename token.
--- a/usr/src/lib/libbsm/common/audit_allocate.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/audit_allocate.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,13 +19,14 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/types.h>
+#include <tsol/label.h>
 #include <bsm/audit.h>
 #include <bsm/libbsm.h>
 #include <bsm/audit_private.h>
@@ -136,6 +136,8 @@
 		}
 		(void) au_write(ad, au_to_newgroups(ng, grplst));
 	}
+	if (is_system_labeled())
+		(void) au_write(ad, au_to_mylabel());
 
 	if (status)
 		(void) au_write(ad, au_to_exit(status, -1));
--- a/usr/src/lib/libbsm/common/audit_ftpd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/audit_ftpd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <netinet/in.h>
+#include <tsol/label.h>
 
 #include <bsm/audit.h>
 #include <bsm/audit_record.h>
@@ -187,6 +187,9 @@
 	(void) au_write(rd, au_to_subject_ex(uid, uid, gid,
 		ruid, rgid, pid, pid, &info.ai_termid));
 
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
+
 	/* add return token */
 	errno = 0;
 	if (err) {
@@ -291,6 +294,9 @@
 	(void) au_write(rd, au_to_subject_ex(info.ai_auid, euid,
 		egid, uid, gid, pid, pid, &info.ai_termid));
 
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
+
 	/* add return token */
 	errno = 0;
 #ifdef _LP64
--- a/usr/src/lib/libbsm/common/audit_rexd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/audit_rexd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -39,6 +38,7 @@
 #include <syslog.h>
 #include <pwd.h>
 #include <netinet/in.h>
+#include <tsol/label.h>
 #include <locale.h>
 #include "generic.h"
 
@@ -204,6 +204,8 @@
 	(void) au_write(rd,
 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid,
 			&info.ai_termid));
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
 
 	/* add reason for failure */
 	(void) au_write(rd, au_to_text(msg));
@@ -328,6 +330,8 @@
 	(void) au_write(rd,
 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid,
 			&info.ai_termid));
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
 
 	/* add hostname of machine requesting service */
 
--- a/usr/src/lib/libbsm/common/audit_rexecd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/audit_rexecd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -39,6 +38,7 @@
 #include <syslog.h>
 #include <pwd.h>
 #include <netinet/in.h>
+#include <tsol/label.h>
 #include <locale.h>
 #include "generic.h"
 
@@ -197,6 +197,8 @@
 	/* add subject token */
 	(void) au_write(rd,
 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid, &tid));
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
 
 	/* add reason for failure */
 	(void) au_write(rd, au_to_text(msg));
@@ -306,6 +308,8 @@
 	/* add subject token */
 	(void) au_write(rd,
 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid, &tid));
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
 
 	/* add hostname of machine requesting service */
 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
--- a/usr/src/lib/libbsm/common/audit_rshd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/audit_rshd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -37,6 +36,7 @@
 #include <string.h>
 #include <syslog.h>
 #include <netinet/in.h>
+#include <tsol/label.h>
 #include <locale.h>
 #include <unistd.h>
 #include <generic.h>
@@ -134,6 +134,8 @@
 
 	(void) au_write(rd, au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid,
 		&info.ai_termid));
+	if (is_system_labeled())
+		(void) au_write(rd, au_to_mylabel());
 
 	gtxt = dgettext(bsm_dom, "cmd %s");
 	tlen = strlen(gtxt) + strlen(cmdbuf) + 1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libbsm/common/devalloc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,1723 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <synch.h>
+#include <strings.h>
+#include <string.h>
+#include <libintl.h>
+#include <errno.h>
+#include <auth_list.h>
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
+
+#define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
+
+extern int _readbufline(char *, int, char *, int, int *);
+extern char *strtok_r(char *, const char *, char **);
+extern char *_strtok_escape(char *, char *, char **);
+extern int getdaon(void);
+extern int da_matchname(devalloc_t *, char *);
+extern int da_match(devalloc_t *, da_args *);
+extern int dmap_matchname(devmap_t *, char *);
+extern int dm_match(devmap_t *, da_args *);
+
+/*
+ * The following structure is for recording old entries to be retained.
+ * We read the entries from the database into a linked list in memory,
+ * then turn around and write them out again.
+ */
+typedef struct strentry {
+	struct strentry	*se_next;
+	char		se_str[4096 + 1];
+} strentry_t;
+
+/*
+ * da_check_longindevperm -
+ *	reads /etc/logindevperm and checks if specified device is in the file.
+ *	returns 1 if specified device found in /etc/logindevperm, else returns 0
+ */
+int
+da_check_logindevperm(char *devname)
+{
+	int		ret = 0;
+	int		fd = -1;
+	int		nlen, plen, slen, lineno, fsize;
+	char		line[MAX_CANON];
+	char		*field_delims = " \t\n";
+	char		*fbuf = NULL;
+	char		*ptr, *device;
+	char		*lasts = NULL;
+	FILE		*fp;
+	struct stat	f_stat;
+
+	/*
+	 * check if /etc/logindevperm exists and get its size
+	 */
+	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
+		return (0);
+	if (fstat(fd, &f_stat) != 0) {
+		(void) close(fd);
+		return (0);
+	}
+	fsize = f_stat.st_size;
+	if ((fbuf = (char *)malloc(fsize)) == NULL) {
+		(void) close(fd);
+		return (0);
+	}
+	if ((fp = fdopen(fd, "r")) == NULL) {
+		free(fbuf);
+		(void) close(fd);
+		return (0);
+	}
+
+	/*
+	 * read and parse /etc/logindevperm
+	 */
+	plen = nlen = lineno = 0;
+	while (fgets(line, MAX_CANON, fp) != NULL) {
+		lineno++;
+		if ((ptr = strchr(line, '#')) != NULL)
+			*ptr = '\0';	/* handle comments */
+		if (strtok_r(line, field_delims, &lasts) == NULL)
+			continue;	/* ignore blank lines */
+		if (strtok_r(NULL, field_delims, &lasts) == NULL)
+			/* invalid entry */
+			continue;
+		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
+			/* empty device list */
+			continue;
+		nlen = strlen(ptr) + 1;		/* +1 terminator */
+		nlen += (plen + 1);
+		if (plen == 0)
+			slen = snprintf(fbuf, nlen, "%s", ptr);
+		else
+			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
+		if (slen >= fsize) {
+			fbuf[0] = '\0';
+			(void) fclose(fp);
+			return (slen);
+		}
+		plen += slen;
+	}
+	(void) fclose(fp);
+
+	/*
+	 * check if devname exists in /etc/logindevperm
+	 */
+	device = strtok_r(fbuf, ":", &lasts);
+	while (device != NULL) {
+		/*
+		 * device and devname may be one of these types -
+		 *    /dev/xx
+		 *    /dev/xx*
+		 *    /dev/dir/xx
+		 *    /dev/dir/xx*
+		 *    /dev/dir/"*"
+		 */
+		if (strcmp(device, devname) == 0) {
+			/* /dev/xx, /dev/dir/xx */
+			free(fbuf);
+			return (1);
+		}
+		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
+			/* all wildcard types */
+			*ptr = '\0';
+			if (strncmp(device, devname, strlen(device)) == 0) {
+				free(fbuf);
+				return (1);
+			}
+		}
+		device = strtok_r(NULL, ":", &lasts);
+	}
+
+	return (ret);
+}
+
+/*
+ * _da_read_file -
+ *	establishes readers/writer lock on fname; reads in the file if its
+ *	contents changed since the last time we read it.
+ *	returns size of buffer read, or -1 on failure.
+ */
+int
+_da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
+    int flag)
+{
+	int		fd = -1;
+	int		fsize = 0;
+	time_t		newtime;
+	FILE		*fp = NULL;
+	struct stat	f_stat;
+
+	if (flag & DA_FORCE)
+		*ftime = 0;
+
+	/* check the size and the time stamp on the file */
+	if (rw_rdlock(flock) != 0)
+		return (-1);
+	if (stat(fname, &f_stat) != 0) {
+		(void) rw_unlock(flock);
+		return (-1);
+	}
+	fsize = f_stat.st_size;
+	newtime = f_stat.st_mtime;
+	(void) rw_unlock(flock);
+
+	while (newtime > *ftime) {
+		/*
+		 * file has been modified since we last read it; or this
+		 * is a forced read.
+		 * read file into the buffer with rw lock.
+		 */
+		if (rw_wrlock(flock) != 0)
+			return (-1);
+		if ((fp = fopen(fname, "r")) == NULL) {
+			(void) rw_unlock(flock);
+			return (-1);
+		}
+		fd = fileno(fp);
+		if (*fbuf != NULL) {
+			free(*fbuf);
+			*fbuf = NULL;
+		}
+		if ((*fbuf = malloc(fsize)) == NULL) {
+			(void) rw_unlock(flock);
+			(void) close(fd);
+			return (-1);
+		}
+		if (read(fd, *fbuf, fsize) < fsize) {
+			free(*fbuf);
+			(void) rw_unlock(flock);
+			(void) close(fd);
+			return (-1);
+		}
+		(void) rw_unlock(flock);
+		/*
+		 * verify that the file did not change just after we read it.
+		 */
+		if (rw_rdlock(flock) != 0) {
+			free(*fbuf);
+			(void) close(fd);
+			return (-1);
+		}
+		if (stat(fname, &f_stat) != 0) {
+			free(*fbuf);
+			(void) rw_unlock(flock);
+			(void) close(fd);
+			return (-1);
+		}
+		fsize = f_stat.st_size;
+		newtime = f_stat.st_mtime;
+		(void) rw_unlock(flock);
+		(void) close(fd);
+		*ftime = newtime;
+	}
+
+	return (fsize);
+}
+
+/*
+ * _update_zonename -
+ *	add/remove current zone's name to the given devalloc_t.
+ */
+void
+_update_zonename(da_args *dargs, devalloc_t *dap)
+{
+	int		i, j;
+	int		oldsize, newsize;
+	int		has_zonename = 0;
+	char		*zonename;
+	kva_t		*newkva, *oldkva;
+	kv_t		*newdata, *olddata;
+	devinfo_t	*devinfo;
+
+	devinfo = dargs->devinfo;
+	oldkva = dap->da_devopts;
+	if (oldkva == NULL) {
+		if (dargs->optflag & DA_REMOVE_ZONE)
+			return;
+		if (dargs->optflag & DA_ADD_ZONE) {
+			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
+			    KV_TOKEN_DELIMIT);
+			if (newkva != NULL)
+				dap->da_devopts = newkva;
+			return;
+		}
+	}
+	newsize = oldsize = oldkva->length;
+	if (kva_match(oldkva, DAOPT_ZONE))
+		has_zonename = 1;
+	if (dargs->optflag & DA_ADD_ZONE) {
+		if ((zonename = index(devinfo->devopts, '=')) == NULL)
+			return;
+		zonename++;
+		if (has_zonename) {
+			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
+			return;
+		}
+		newsize += 1;
+	} else if (dargs->optflag & DA_REMOVE_ZONE) {
+		if (has_zonename) {
+			newsize -= 1;
+			if (newsize == 0) {
+				/*
+				 * If zone name was the only key/value pair,
+				 * put 'reserved' in the empty slot.
+				 */
+				_kva_free(oldkva);
+				dap->da_devopts = NULL;
+				return;
+			}
+		} else {
+			return;
+		}
+	}
+	newkva = _new_kva(newsize);
+	newkva->length = 0;
+	newdata = newkva->data;
+	olddata = oldkva->data;
+	for (i = 0, j = 0; i < oldsize; i++) {
+		if ((dargs->optflag & DA_REMOVE_ZONE) &&
+		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
+			continue;
+		newdata[j].key = strdup(olddata[i].key);
+		newdata[j].value = strdup(olddata[i].value);
+		newkva->length++;
+		j++;
+	}
+	if (dargs->optflag & DA_ADD_ZONE) {
+		newdata[j].key = strdup(DAOPT_ZONE);
+		newdata[j].value = strdup(zonename);
+		newkva->length++;
+	}
+	_kva_free(oldkva);
+	dap->da_devopts = newkva;
+}
+
+/*
+ * _dmap2str -
+ *	converts a device_map entry into a printable string
+ *	returns 0 on success, -1 on error.
+ */
+/*ARGSUSED*/
+static int
+_dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep)
+{
+	int	length;
+
+	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s%s",
+	    dmp->dmap_devtype, sep);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s\n",
+	    dmp->dmap_devlist);
+	if (length >= size)
+		return (-1);
+	return (0);
+}
+
+/*
+ * _dmap2strentry -
+ *	calls dmap2str to break given devmap_t into printable entry.
+ *	returns pointer to decoded entry, NULL on error.
+ */
+static strentry_t *
+_dmap2strentry(da_args *dargs, devmap_t *devmapp)
+{
+	strentry_t	*sep;
+
+	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
+		return (NULL);
+	if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str),
+	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
+		free(sep);
+		return (NULL);
+	}
+	return (sep);
+}
+
+/*
+ * fix_optstr -
+ * 	removes trailing ':' from buf.
+ */
+void
+fix_optstr(char *buf)
+{
+	char	*p = NULL;
+
+	if (p = rindex(buf, ':'))
+		*p = ';';
+}
+
+/*
+ * _da2str -
+ *	converts a device_allocate entry into a printable string
+ *	returns 0 on success, -1 on error.
+ */
+static int
+_da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
+    const char *osep)
+{
+	int	length;
+	int	matching_entry = 0;
+	char	**dnames;
+
+	if (dargs->optflag & DA_UPDATE &&
+	    (dargs->optflag & DA_ADD_ZONE ||
+	    dargs->optflag & DA_REMOVE_ZONE) &&
+	    dargs->devnames) {
+		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
+			if (da_matchname(dap, *dnames)) {
+				matching_entry = 1;
+				break;
+			}
+		}
+	}
+	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s%s",
+	    dap->da_devtype, sep);
+	if (length >= size)
+		return (-1);
+	if (matching_entry)
+		_update_zonename(dargs, dap);
+	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
+	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
+		length += snprintf(buf + length, size - length, "%s%s",
+		    DA_RESERVED, sep);
+	} else {
+		if (_kva2str(dap->da_devopts, buf + length, size - length,
+		    KV_ASSIGN, (char *)osep) != 0)
+			return (-1);
+		length = strlen(buf);
+	}
+	if (dap->da_devopts)
+		fix_optstr(buf);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s%s",
+	    DA_RESERVED, sep);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s%s",
+	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
+	if (length >= size)
+		return (-1);
+	length += snprintf(buf + length, size - length, "%s\n",
+	    dap->da_devexec ? dap->da_devexec : "");
+	if (length >= size)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * _da2strentry -
+ *	calls da2str to break given devalloc_t into printable entry.
+ *	returns pointer to decoded entry, NULL on error.
+ */
+static strentry_t *
+_da2strentry(da_args *dargs, devalloc_t *dap)
+{
+	strentry_t	*sep;
+
+	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
+		return (NULL);
+	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
+	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
+		free(sep);
+		return (NULL);
+	}
+	return (sep);
+}
+
+/*
+ * _def2str
+ *	converts da_defs_t into a printable string.
+ *	returns 0 on success, -1 on error.
+ */
+static int
+_def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
+{
+	int length;
+
+	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
+	if (length >= size)
+		return (-1);
+	if (da_defs->devopts) {
+		if (_kva2str(da_defs->devopts, buf + length, size - length,
+		    KV_ASSIGN, KV_DELIMITER) != 0)
+			return (-1);
+		length = strlen(buf);
+	}
+	if (length >= size)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * _def2strentry
+ *	calls _def2str to break given da_defs_t into printable entry.
+ *	returns pointer decoded entry, NULL on error.
+ */
+static strentry_t *
+_def2strentry(da_defs_t *da_defs)
+{
+	strentry_t	*sep;
+
+	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
+		return (NULL);
+	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
+	    KV_TOKEN_DELIMIT) != 0) {
+		free(sep);
+		return (NULL);
+	}
+
+	return (sep);
+}
+
+/*
+ * _build_defattrs
+ *	cycles through all defattr entries, stores them in memory. removes
+ *	entries with the given search_key (device type).
+ *	returns 0 if given entry not found, 1 if given entry removed, 2 on
+ *	error.
+ */
+static int
+_build_defattrs(da_args *dargs, strentry_t **head_defent)
+{
+	int		rc = 0;
+	da_defs_t	*da_defs;
+	strentry_t	*tail_str, *tmp_str;
+
+	setdadefent();
+	while ((da_defs = getdadefent()) != NULL) {
+		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
+		if (rc && dargs->optflag & DA_ADD &&
+		    !(dargs->optflag & DA_FORCE)) {
+			/*
+			 * During DA_ADD, we keep an existing entry unless
+			 * we have DA_FORCE set to override that entry.
+			 */
+			dargs->optflag |= DA_NO_OVERRIDE;
+			rc = 0;
+		}
+		if (rc == 0) {
+			tmp_str = _def2strentry(da_defs);
+			if (tmp_str == NULL) {
+				freedadefent(da_defs);
+				enddadefent();
+				return (2);
+			}
+			/* retaining defattr entry: tmp_str->se_str */
+			tmp_str->se_next = NULL;
+			if (*head_defent == NULL) {
+				*head_defent = tail_str = tmp_str;
+			} else {
+				tail_str->se_next = tmp_str;
+				tail_str = tmp_str;
+			}
+		}
+		freedadefent(da_defs);
+	}
+	enddadefent();
+
+	return (rc);
+}
+
+/*
+ * _build_lists -
+ *	cycles through all the entries, stores them in memory. removes entries
+ *	with the given search_key (device name or type).
+ *	returns 0 if given entry not found, 1 if given entry removed, 2 on
+ *	error.
+ */
+static int
+_build_lists(da_args *dargs, strentry_t **head_devallocp,
+    strentry_t **head_devmapp)
+{
+	int		rc = 0;
+	devalloc_t	*devallocp;
+	devmap_t	*devmapp;
+	strentry_t	*tail_str;
+	strentry_t	*tmp_str;
+
+	if (dargs->optflag & DA_MAPS_ONLY)
+		goto dmap_only;
+
+	/* build device_allocate */
+	setdaent();
+	while ((devallocp = getdaent()) != NULL) {
+		rc = da_match(devallocp, dargs);
+		if (rc && dargs->optflag & DA_ADD &&
+		    !(dargs->optflag & DA_FORCE)) {
+			/*
+			 * During DA_ADD, we keep an existing entry unless
+			 * we have DA_FORCE set to override that entry.
+			 */
+			dargs->optflag |= DA_NO_OVERRIDE;
+			rc = 0;
+		}
+		if (rc == 0) {
+			tmp_str = _da2strentry(dargs, devallocp);
+			if (tmp_str == NULL) {
+				freedaent(devallocp);
+				enddaent();
+				return (2);
+			}
+			/* retaining devalloc entry: tmp_str->se_str */
+			tmp_str->se_next = NULL;
+			if (*head_devallocp == NULL) {
+				*head_devallocp = tail_str = tmp_str;
+			} else {
+				tail_str->se_next = tmp_str;
+				tail_str = tmp_str;
+			}
+		}
+		freedaent(devallocp);
+	}
+	enddaent();
+
+dmap_only:
+	if (dargs->optflag & DA_ALLOC_ONLY)
+		return (rc);
+
+	/* build device_maps */
+	rc = 0;
+	setdmapent();
+	while ((devmapp = getdmapent()) != NULL) {
+		rc = dm_match(devmapp, dargs);
+		if (rc && dargs->optflag & DA_ADD &&
+		    !(dargs->optflag & DA_FORCE)) {
+			/*
+			 * During DA_ADD, we keep an existing entry unless
+			 * we have DA_FORCE set to override that entry.
+			 */
+			dargs->optflag |= DA_NO_OVERRIDE;
+			rc = 0;
+		}
+		if (rc == 0) {
+			tmp_str = _dmap2strentry(dargs, devmapp);
+			if (tmp_str == NULL) {
+				freedmapent(devmapp);
+				enddmapent();
+				return (2);
+			}
+			/* retaining devmap entry: tmp_str->se_str */
+			tmp_str->se_next = NULL;
+			if (*head_devmapp == NULL) {
+				*head_devmapp = tail_str = tmp_str;
+			} else {
+				tail_str->se_next = tmp_str;
+				tail_str = tmp_str;
+			}
+		}
+		freedmapent(devmapp);
+	}
+	enddmapent();
+
+	return (rc);
+}
+
+/*
+ * _write_defattrs
+ *	writes current entries to devalloc_defaults.
+ */
+static void
+_write_defattrs(FILE *fp, strentry_t *head_defent)
+{
+	strentry_t *tmp_str;
+
+	for (tmp_str = head_defent; tmp_str != NULL;
+	    tmp_str = tmp_str->se_next) {
+		(void) fputs(tmp_str->se_str, fp);
+		(void) fputs("\n", fp);
+	}
+
+}
+
+/*
+ * _write_device_allocate -
+ *	writes current entries in the list to device_allocate.
+ */
+static void
+_write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
+{
+	int		is_on = -1;
+	strentry_t	*tmp_str;
+	struct stat	dastat;
+
+	(void) fseek(dafp, (off_t)0, SEEK_SET);
+
+	/*
+	 * if the devalloc on/off string existed before,
+	 * put it back before anything else.
+	 * we need to check for the string only if the file
+	 * exists.
+	 */
+	if (stat(odevalloc, &dastat) == 0) {
+		is_on = da_is_on();
+		if (is_on == 0)
+			(void) fputs(DA_OFF_STR, dafp);
+		else if (is_on == 1)
+			(void) fputs(DA_ON_STR, dafp);
+	}
+	tmp_str = head_devallocp;
+	while (tmp_str) {
+		(void) fputs(tmp_str->se_str, dafp);
+		(void) fputs("\n", dafp);
+		tmp_str = tmp_str->se_next;
+	}
+}
+
+/*
+ * _write_device_maps -
+ *	writes current entries in the list to device_maps.
+ */
+static void
+_write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
+{
+	strentry_t	*tmp_str;
+
+	(void) fseek(dmfp, (off_t)0, SEEK_SET);
+
+	tmp_str = head_devmapp;
+	while (tmp_str) {
+		(void) fputs(tmp_str->se_str, dmfp);
+		(void) fputs("\n", dmfp);
+		tmp_str = tmp_str->se_next;
+	}
+}
+
+/*
+ * _write_new_defattrs
+ *	writes the new entry to devalloc_defaults.
+ *	returns 0 on success, -1 on error.
+ */
+static int
+_write_new_defattrs(FILE *fp, da_args *dargs)
+{
+	int		count;
+	char		*tok = NULL, *tokp = NULL;
+	char		*lasts;
+	devinfo_t	*devinfo = dargs->devinfo;
+
+	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
+		return (-1);
+	if (!devinfo->devopts)
+		return (0);
+	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
+	    KV_TOKEN_DELIMIT);
+	if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
+		(void) strcpy(tokp, devinfo->devopts);
+		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
+			(void) fprintf(fp, "%s", tok);
+			count = 1;
+		}
+		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
+			if (count)
+				(void) fprintf(fp, "%s", KV_DELIMITER);
+			(void) fprintf(fp, "%s", tok);
+			count++;
+		}
+	} else {
+		(void) fprintf(fp, "%s", devinfo->devopts);
+	}
+
+	return (0);
+}
+
+/*
+ * _write_new_entry -
+ *	writes the new devalloc_t to device_allocate or the new devmap_t to
+ *	device_maps.
+ *	returns 0 on success, -1 on error.
+ */
+static int
+_write_new_entry(FILE *fp, da_args *dargs, int flag)
+{
+	int		count;
+	char		*tok = NULL, *tokp = NULL;
+	char		*lasts;
+	devinfo_t	*devinfo = dargs->devinfo;
+
+	if (flag & DA_MAPS_ONLY)
+		goto dmap_only;
+
+	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
+		return (-1);
+
+	(void) fprintf(fp, "%s%s\\\n\t",
+	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
+	(void) fprintf(fp, "%s%s\\\n\t",
+	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
+	if (devinfo->devopts == NULL) {
+		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
+		    KV_DELIMITER);
+	} else {
+		if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
+			(void) strcpy(tokp, devinfo->devopts);
+			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
+			    NULL) {
+				(void) fprintf(fp, "%s", tok);
+				count = 1;
+			}
+			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
+			    &lasts)) != NULL) {
+				if (count)
+					(void) fprintf(fp, "%s",
+					    KV_TOKEN_DELIMIT "\\\n\t");
+				(void) fprintf(fp, "%s", tok);
+				count++;
+			}
+			if (count)
+				(void) fprintf(fp, "%s",
+				    KV_DELIMITER "\\\n\t");
+		} else {
+			(void) fprintf(fp, "%s%s", devinfo->devopts,
+			    KV_DELIMITER "\\\n\t");
+		}
+	}
+	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
+	(void) fprintf(fp, "%s%s\\\n\t",
+	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
+	    KV_DELIMITER);
+	(void) fprintf(fp, "%s\n",
+	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
+
+dmap_only:
+	if (flag & DA_ALLOC_ONLY)
+		return (0);
+
+	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
+		return (-1);
+
+	(void) fprintf(fp, "%s%s\\\n",
+	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
+	(void) fprintf(fp, "\t%s%s\\\n",
+	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
+	(void) fprintf(fp, "\t%s\n",
+	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
+
+	return (0);
+}
+
+/*
+ * _da_lock_devdb -
+ *	locks the database files; lock can be either broken explicitly by
+ *	closing the fd of the lock file, or it expires automatically at process
+ *	termination.
+ * 	returns fd of the lock file or -1 on error.
+ */
+int
+_da_lock_devdb(char *rootdir)
+{
+	int		lockfd = -1;
+	char		*lockfile;
+	char		path[MAXPATHLEN];
+	int		size = sizeof (path);
+
+	if (rootdir == NULL) {
+		lockfile = DA_DB_LOCK;
+	} else {
+		path[0] = '\0';
+		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
+			return (-1);
+		lockfile = path;
+	}
+
+	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
+		/* cannot open lock file */
+		return (-1);
+
+	(void) fchown(lockfd, DA_UID, DA_GID);
+
+	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
+		/* cannot position lock file */
+		(void) close(lockfd);
+		return (-1);
+	}
+	if (lockf(lockfd, F_TLOCK, 0) == -1) {
+		/* cannot set lock */
+		(void) close(lockfd);
+		return (-1);
+	}
+	(void) utime(lockfile, NULL);
+
+	return (lockfd);
+}
+
+/*
+ * da_open_devdb -
+ *	opens one or both database files - device_allocate, device_maps - in
+ *	the specified mode.
+ *	locks the database files; lock is either broken explicitly by the
+ *	caller by closing the lock file fd, or it expires automatically at
+ *	process termination.
+ *	writes the file pointer of opened file in the input args - dafp, dmfp.
+ *	returns fd of the lock file on success, -2 if database file does not
+ *	exist, -1 on other errors.
+ */
+int
+da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
+{
+	int	oflag = 0;
+	int	fda = -1;
+	int	fdm = -1;
+	int	lockfd = -1;
+	char	*fname;
+	char	*fmode;
+	char	path[MAXPATHLEN];
+	FILE	*devfile;
+
+	if ((dafp == NULL) && (dmfp == NULL))
+		return (-1);
+
+	if (flag & DA_RDWR) {
+		oflag = DA_RDWR;
+		fmode = "r+";
+	} else if (flag & DA_RDONLY) {
+		oflag = DA_RDONLY;
+		fmode = "r";
+	}
+
+	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
+		return (-1);
+
+	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
+		goto dmap_only;
+
+	path[0] = '\0';
+
+	/*
+	 * open the device allocation file
+	 */
+	if (rootdir == NULL) {
+		fname = DEVALLOC;
+	} else {
+		if (snprintf(path, sizeof (path), "%s%s", rootdir,
+		    DEVALLOC) >= sizeof (path)) {
+			if (lockfd != -1)
+				(void) close(lockfd);
+			return (-1);
+		}
+		fname = path;
+	}
+	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
+		if (lockfd != -1)
+			(void) close(lockfd);
+		return ((errno == ENOENT) ? -2 : -1);
+	}
+	if ((devfile = fdopen(fda, fmode)) == NULL) {
+		(void) close(fda);
+		if (lockfd != -1)
+			(void) close(lockfd);
+		return (-1);
+	}
+	*dafp = devfile;
+	(void) fchmod(fda, DA_DBMODE);
+
+	if ((flag & DA_ALLOC_ONLY))
+		goto out;
+
+dmap_only:
+	path[0] = '\0';
+	/*
+	 * open the device map file
+	 */
+	if (rootdir == NULL) {
+		fname = DEVMAP;
+	} else {
+		if (snprintf(path, sizeof (path), "%s%s", rootdir,
+		    DEVMAP) >= sizeof (path)) {
+			(void) close(fda);
+			if (lockfd != -1)
+				(void) close(lockfd);
+			return (-1);
+		}
+		fname = path;
+	}
+
+	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
+		if (lockfd != -1)
+			(void) close(lockfd);
+		return ((errno == ENOENT) ? -2 : -1);
+	}
+
+	if ((devfile = fdopen(fdm, fmode)) == NULL) {
+		(void) close(fdm);
+		(void) close(fda);
+		if (lockfd != -1)
+			(void) close(lockfd);
+		return (-1);
+	}
+	*dmfp = devfile;
+	(void) fchmod(fdm, DA_DBMODE);
+
+out:
+	return (lockfd);
+}
+
+/*
+ * _record_on_off -
+ *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
+ *	returns 0 on success, -1 on error.
+ */
+static int
+_record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
+{
+	int		dafd;
+	int		nsize;
+	int		nitems = 1;
+	int		actionlen;
+	int		str_found = 0;
+	int		len = 0, nlen = 0, plen = 0;
+	char		*ptr = NULL;
+	char		*actionstr;
+	char		*nbuf = NULL;
+	char		line[MAX_CANON];
+	struct stat	dastat;
+
+	if (dargs->optflag & DA_ON)
+		actionstr = DA_ON_STR;
+	else
+		actionstr = DA_OFF_STR;
+	actionlen = strlen(actionstr);
+	dafd = fileno(dafp);
+	if (fstat(dafd, &dastat) == -1)
+		return (-1);
+
+	/* check the old device_allocate for on/off string */
+	ptr = fgets(line, MAX_CANON, dafp);
+	if (ptr != NULL) {
+		if ((strcmp(line, DA_ON_STR) == 0) ||
+		    (strcmp(line, DA_OFF_STR) == 0)) {
+			str_found = 1;
+			nsize = dastat.st_size;
+		}
+	}
+	if (!ptr || !str_found) {
+		/*
+		 * the file never had either the on or the off string;
+		 * make room for it.
+		 */
+		str_found = 0;
+		nsize = dastat.st_size + actionlen + 1;
+	}
+	if ((nbuf = (char *)malloc(nsize)) == NULL)
+		return (-1);
+	nbuf[0] = '\0';
+	/* put the on/off string */
+	(void) strcpy(nbuf, actionstr);
+	nlen = strlen(nbuf);
+	plen = nlen;
+	if (ptr && !str_found) {
+		/* now put the first line that we read in fgets */
+		nlen = plen + strlen(line) + 1;
+		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
+		if (len >= nsize) {
+			free(nbuf);
+			return (-1);
+		}
+		plen += len;
+	}
+
+	/* now get the rest of the old file */
+	while (fgets(line, MAX_CANON, dafp) != NULL) {
+		nlen = plen + strlen(line) + 1;
+		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
+		if (len >= nsize) {
+			free(nbuf);
+			return (-1);
+		}
+		plen += len;
+	}
+	len = strlen(nbuf) + 1;
+	if (len < nsize)
+		nbuf[len] = '\n';
+
+	/* write the on/off str + the old device_allocate to the temp file */
+	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
+		free(nbuf);
+		return (-1);
+	}
+
+	free(nbuf);
+
+	return (0);
+}
+
+/*
+ * da_update_defattrs -
+ *	writes default attributes to devalloc_defaults
+ *	returns 0 on success, -1 on error.
+ */
+int
+da_update_defattrs(da_args *dargs)
+{
+	int		rc = 0, lockfd = 0, tmpfd = 0;
+	char		*defpath = DEFATTRS;
+	char		*tmpdefpath = TMPATTRS;
+	FILE		*tmpfp = NULL;
+	struct stat	dstat;
+	strentry_t	*head_defent = NULL;
+
+	if (dargs == NULL)
+		return (0);
+	if ((lockfd = _da_lock_devdb(NULL)) == -1)
+		return (-1);
+	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
+		(void) close(lockfd);
+		return (-1);
+	}
+	(void) fchown(tmpfd, DA_UID, DA_GID);
+	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
+		(void) close(tmpfd);
+		(void) unlink(tmpdefpath);
+		(void) close(lockfd);
+		return (-1);
+	}
+	/*
+	 * examine all entries, remove an old one if required, check
+	 * if a new one needs to be added.
+	 */
+	if (stat(defpath, &dstat) == 0) {
+		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
+			if (rc == 1) {
+				(void) close(tmpfd);
+				(void) unlink(tmpdefpath);
+				(void) close(lockfd);
+				return (rc);
+			}
+		}
+	}
+	/*
+	 * write back any existing entries.
+	 */
+	_write_defattrs(tmpfp, head_defent);
+
+	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
+		/* add new entries */
+		rc = _write_new_defattrs(tmpfp, dargs);
+		(void) fclose(tmpfp);
+	} else {
+		(void) fclose(tmpfp);
+	}
+	if (rename(tmpdefpath, defpath) != 0) {
+		rc = -1;
+		(void) unlink(tmpdefpath);
+	}
+	(void) close(lockfd);
+
+	return (rc);
+}
+
+/*
+ * da_update_device -
+ *	writes devices entries to device_allocate and device_maps.
+ * 	returns 0 on success, -1 on error.
+ */
+int
+da_update_device(da_args *dargs)
+{
+	int		rc;
+	int		tafd = -1, tmfd = -1;
+	int		lockfd = -1;
+	char		*rootdir = NULL;
+	char		*apathp = NULL, *mpathp = NULL, *dapathp = NULL,
+			*dmpathp = NULL;
+	char		apath[MAXPATHLEN], mpath[MAXPATHLEN],
+			dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
+	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
+	struct stat	dastat;
+	devinfo_t	*devinfo;
+	strentry_t	*head_devmapp = NULL;
+	strentry_t	*head_devallocp = NULL;
+
+	if (dargs == NULL)
+		return (0);
+
+	rootdir = dargs->rootdir;
+	devinfo = dargs->devinfo;
+
+	/*
+	 * adding/removing entries should be done in both
+	 * device_allocate and device_maps. updates can be
+	 * done in both or either of the files.
+	 */
+	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
+		if (dargs->optflag & DA_ALLOC_ONLY ||
+		    dargs->optflag & DA_MAPS_ONLY)
+			return (0);
+	}
+
+	/*
+	 * name, type and list are required fields for adding a new
+	 * device.
+	 */
+	if ((dargs->optflag & DA_ADD) &&
+	    ((devinfo->devname == NULL) ||
+	    (devinfo->devtype == NULL) ||
+	    (devinfo->devlist == NULL))) {
+		return (-1);
+	}
+
+	if (rootdir != NULL) {
+		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
+		    TMPALLOC) >= sizeof (apath))
+			return (-1);
+		apathp = apath;
+		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
+		    DEVALLOC) >= sizeof (dapath))
+			return (-1);
+		dapathp = dapath;
+		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
+			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
+			    TMPMAP) >= sizeof (mpath))
+				return (-1);
+			mpathp = mpath;
+			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
+			    DEVMAP) >= sizeof (dmpath))
+				return (-1);
+			dmpathp = dmpath;
+		}
+	} else {
+		apathp = TMPALLOC;
+		dapathp = DEVALLOC;
+		mpathp = TMPMAP;
+		dmpathp = DEVMAP;
+	}
+
+	if (dargs->optflag & DA_MAPS_ONLY)
+		goto dmap_only;
+
+	/*
+	 * Check if we are here just to record on/off status of
+	 * device_allocation.
+	 */
+	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
+		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
+		    DA_RDONLY|DA_ALLOC_ONLY);
+	else
+		lockfd = _da_lock_devdb(rootdir);
+	if (lockfd == -1)
+		return (-1);
+
+	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
+		(void) close(lockfd);
+		(void) fclose(dafp);
+		return (-1);
+	}
+	(void) fchown(tafd, DA_UID, DA_GID);
+	if ((tafp = fdopen(tafd, "r+")) == NULL) {
+		(void) close(tafd);
+		(void) unlink(apathp);
+		(void) fclose(dafp);
+		(void) close(lockfd);
+		return (-1);
+	}
+
+	/*
+	 * We don't need to parse the file if we are here just to record
+	 * on/off status of device_allocation.
+	 */
+	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
+		if (_record_on_off(dargs, tafp, dafp) == -1) {
+			(void) close(tafd);
+			(void) unlink(apathp);
+			(void) fclose(dafp);
+			(void) close(lockfd);
+			return (-1);
+		}
+		(void) fclose(dafp);
+		goto out;
+	}
+
+	/*
+	 * examine all the entries, remove an old one if forced to,
+	 * and check that they are suitable for updating.
+	 *  we need to do this only if the file exists already.
+	 */
+	if (stat(dapathp, &dastat) == 0) {
+		if ((rc = _build_lists(dargs, &head_devallocp,
+		    &head_devmapp)) != 0) {
+			if (rc != 1) {
+				(void) close(tafd);
+				(void) unlink(apathp);
+				(void) close(lockfd);
+				return (rc);
+			}
+		}
+	}
+
+	/*
+	 * write back any existing devalloc entries, along with
+	 * the devalloc on/off string.
+	 */
+	_write_device_allocate(dapathp, tafp, head_devallocp);
+
+	if (dargs->optflag & DA_ALLOC_ONLY)
+		goto out;
+
+dmap_only:
+	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
+		(void) close(tafd);
+		(void) unlink(apathp);
+		(void) close(lockfd);
+		return (-1);
+	}
+	(void) fchown(tmfd, DA_UID, DA_GID);
+	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
+		(void) close(tafd);
+		(void) unlink(apathp);
+		(void) close(tmfd);
+		(void) unlink(mpathp);
+		(void) close(lockfd);
+		return (-1);
+	}
+
+	/* write back any existing devmap entries */
+	if (head_devmapp != NULL)
+		_write_device_maps(tmfp, head_devmapp);
+
+out:
+	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
+		/* add any new entries */
+		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
+		(void) fclose(tafp);
+
+		if (rc == 0)
+			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
+		(void) fclose(tmfp);
+	} else {
+		if (tafp)
+			(void) fclose(tafp);
+		if (tmfp)
+			(void) fclose(tmfp);
+	}
+
+	rc = 0;
+	if (!(dargs->optflag & DA_MAPS_ONLY)) {
+		if (rename(apathp, dapathp) != 0) {
+			rc = -1;
+			(void) unlink(apathp);
+		}
+	}
+	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
+		if (rename(mpathp, dmpathp) != 0) {
+			rc = -1;
+			(void) unlink(mpathp);
+		}
+	}
+
+	(void) close(lockfd);
+
+	return (rc);
+}
+
+/*
+ * da_add_list -
+ *	adds new /dev link name to the linked list of devices.
+ *	returns 0 if link added successfully, -1 on error.
+ */
+int
+da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
+{
+	int		instance;
+	int		nlen, plen;
+	int		new_entry = 0;
+	char		*dtype, *dexec, *tname, *kval;
+	char		*minstr = NULL, *maxstr = NULL;
+	char		dname[DA_MAXNAME];
+	kva_t		*kva;
+	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
+	da_defs_t	*da_defs;
+
+	if (dlist == NULL || link == NULL)
+		return (-1);
+
+	dname[0] = '\0';
+	if (flag & DA_AUDIO) {
+		dentry = dlist->audio;
+		tname = DA_AUDIO_NAME;
+		dtype = DA_AUDIO_TYPE;
+		dexec = DA_DEFAULT_AUDIO_CLEAN;
+	} else if (flag & DA_CD) {
+		dentry = dlist->cd;
+		tname = DA_CD_NAME;
+		dtype = DA_CD_TYPE;
+		dexec = DA_DEFAULT_DISK_CLEAN;
+	} else if (flag & DA_FLOPPY) {
+		dentry = dlist->floppy;
+		tname = DA_FLOPPY_NAME;
+		dtype = DA_FLOPPY_TYPE;
+		dexec = DA_DEFAULT_DISK_CLEAN;
+	} else if (flag & DA_TAPE) {
+		dentry = dlist->tape;
+		tname = DA_TAPE_NAME;
+		dtype = DA_TAPE_TYPE;
+		dexec = DA_DEFAULT_TAPE_CLEAN;
+	} else if (flag & DA_RMDISK) {
+		dentry = dlist->rmdisk;
+		tname = DA_RMDISK_NAME;
+		dtype = DA_RMDISK_TYPE;
+		dexec = DA_DEFAULT_DISK_CLEAN;
+	} else {
+		return (-1);
+	}
+
+	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
+		pentry = nentry;
+		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
+		if (nentry->devinfo.instance == new_instance)
+			/*
+			 * Add the new link name to the list of links
+			 * that the device 'dname' has.
+			 */
+			break;
+	}
+
+	if (nentry == NULL) {
+		/*
+		 * Either this is the first entry ever, or no matching entry
+		 * was found. Create a new one and add to the list.
+		 */
+		if (dentry == NULL)		/* first entry ever */
+			instance = 0;
+		else				/* no matching entry */
+			instance++;
+		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
+		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
+		    NULL)
+			return (-1);
+		if (pentry != NULL)
+			pentry->next = nentry;
+		new_entry = 1;
+		nentry->devinfo.devname = strdup(dname);
+		nentry->devinfo.devtype = dtype;
+		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
+		nentry->devinfo.devexec = dexec;
+		nentry->devinfo.instance = new_instance;
+		/*
+		 * Look for default label range, authorizations and cleaning
+		 * program in devalloc_defaults. If label range is not
+		 * specified in devalloc_defaults, assume it to be admin_low
+		 * to admin_high.
+		 */
+		minstr = DA_DEFAULT_MIN;
+		maxstr = DA_DEFAULT_MAX;
+		setdadefent();
+		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
+			kva = da_defs->devopts;
+			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
+				minstr = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
+				maxstr = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
+				nentry->devinfo.devauths = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
+				nentry->devinfo.devexec = strdup(kval);
+			freedadefent(da_defs);
+		}
+		enddadefent();
+		kval = NULL;
+		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
+		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
+		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
+		    + 1;			/* +1 for terminator */
+		if (kval = (char *)malloc(nlen))
+			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
+			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
+			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
+		nentry->devinfo.devopts = kval;
+
+		nentry->devinfo.devlist = NULL;
+		nentry->next = NULL;
+	}
+
+	nlen = strlen(link) + 1;		/* +1 terminator */
+	if (nentry->devinfo.devlist) {
+		plen = strlen(nentry->devinfo.devlist);
+		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
+	} else {
+		plen = 0;
+	}
+
+	if ((nentry->devinfo.devlist =
+	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
+		if (new_entry) {
+			nentry->devinfo.devname = NULL;
+			free(nentry->devinfo.devname);
+			nentry = NULL;
+			free(nentry);
+			if (pentry != NULL)
+				pentry->next = NULL;
+		}
+		return (-1);
+	}
+
+	if (plen == 0)
+		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
+	else
+		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
+		    " %s", link);
+
+	if (pentry == NULL) {
+		/*
+		 * This is the first entry of this device type.
+		 */
+		if (flag & DA_AUDIO)
+			dlist->audio = nentry;
+		else if (flag & DA_CD)
+			dlist->cd = nentry;
+		else if (flag & DA_FLOPPY)
+			dlist->floppy = nentry;
+		else if (flag & DA_TAPE)
+			dlist->tape = nentry;
+		else if (flag & DA_RMDISK)
+			dlist->rmdisk = nentry;
+	}
+
+	return (0);
+}
+
+/*
+ * da_remove_list -
+ *	removes a /dev link name from the linked list of devices.
+ *	returns type of device if link for that device removed
+ *	successfully, else returns -1 on error.
+ *	if all links for a device are removed, stores that device
+ *	name in devname.
+ */
+int
+da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
+{
+	int		flag;
+	int		remove_dev = 0;
+	int		nlen, plen, slen;
+	char		*lasts, *lname, *oldlist;
+	struct stat	rmstat;
+	deventry_t	*dentry, *current, *prev;
+
+	if (type != NULL)
+		flag = type;
+	else if (link == NULL)
+		return (-1);
+	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
+		flag = DA_AUDIO;
+	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
+	    strstr(link, "sr") || strstr(link, "rsr"))
+		flag = DA_CD;
+	else if (strstr(link, "fd") || strstr(link, "rfd") ||
+	    strstr(link, "diskette") || strstr(link, "rdiskette"))
+		flag = DA_FLOPPY;
+	else if (strstr(link, DA_TAPE_NAME))
+		flag = DA_TAPE;
+	else
+		flag = DA_RMDISK;
+
+	switch (type) {
+	case DA_AUDIO:
+		dentry = dlist->audio;
+		break;
+	case DA_CD:
+		dentry = dlist->cd;
+		break;
+	case DA_FLOPPY:
+		dentry = dlist->floppy;
+		break;
+	case DA_TAPE:
+		dentry = dlist->tape;
+		break;
+	case DA_RMDISK:
+		dentry = dlist->rmdisk;
+		break;
+	default:
+		return (-1);
+	}
+
+	if ((type != NULL) && (link == NULL)) {
+		for (current = dentry, prev = dentry; current != NULL;
+		    current = current->next) {
+			oldlist = strdup(current->devinfo.devlist);
+			for (lname = strtok_r(oldlist, " ", &lasts);
+			    lname != NULL;
+			    lname = strtok_r(NULL, " ", &lasts)) {
+				if (stat(lname, &rmstat) != 0) {
+					remove_dev = 1;
+					goto remove_dev;
+				}
+			}
+			prev = current;
+		}
+		return (-1);
+	}
+
+	for (current = dentry, prev = dentry; current != NULL;
+	    current = current->next) {
+		plen = strlen(current->devinfo.devlist);
+		nlen = strlen(link);
+		if (plen == nlen) {
+			if (strcmp(current->devinfo.devlist, link) == 0) {
+				/* last name in the list */
+				remove_dev = 1;
+				break;
+			}
+		}
+		if (strstr(current->devinfo.devlist, link)) {
+			nlen = plen - nlen + 1;
+			oldlist = strdup(current->devinfo.devlist);
+			if ((current->devinfo.devlist =
+			    (char *)realloc(current->devinfo.devlist,
+			    nlen)) == NULL) {
+				free(oldlist);
+				return (-1);
+			}
+			current->devinfo.devlist[0] = '\0';
+			nlen = plen = slen = 0;
+			for (lname = strtok_r(oldlist, " ", &lasts);
+			    lname != NULL;
+			    lname = strtok_r(NULL, " ", &lasts)) {
+				if (strcmp(lname, link) == 0)
+					continue;
+				nlen = strlen(lname) + plen + 1;
+				if (plen == 0) {
+					slen =
+					    snprintf(current->devinfo.devlist,
+						nlen, "%s", lname);
+				} else {
+					slen =
+					    snprintf(current->devinfo.devlist +
+						plen, nlen - plen, " %s",
+						lname);
+				}
+				plen = plen + slen + 1;
+			}
+			free(oldlist);
+			break;
+		}
+		prev = current;
+	}
+
+remove_dev:
+	if (remove_dev == 1) {
+		(void) strlcpy(devname, current->devinfo.devname, size);
+		free(current->devinfo.devname);
+		free(current->devinfo.devlist);
+		current->devinfo.devname = current->devinfo.devlist = NULL;
+		prev->next = current->next;
+		free(current);
+		current = NULL;
+	}
+	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
+		if (prev->next) {
+			/*
+			 * what we removed above was the first entry
+			 * in the list. make the next entry to be the
+			 * first.
+			 */
+			current = prev->next;
+		} else {
+			/*
+			 * the matching entry was the only entry in the list
+			 * for this type.
+			 */
+			current = NULL;
+		}
+		if (flag & DA_AUDIO)
+			dlist->audio = current;
+		else if (flag & DA_CD)
+			dlist->cd = current;
+		else if (flag & DA_FLOPPY)
+			dlist->floppy = current;
+		else if (flag & DA_TAPE)
+			dlist->tape = current;
+		else if (flag & DA_RMDISK)
+			dlist->rmdisk = current;
+	}
+
+	return (flag);
+}
+
+/*
+ * da_is_on -
+ *	checks if device allocation feature is turned on.
+ *	returns 1 if on, 0 if off, -1 if status string not
+ *	found in device_allocate.
+ */
+int
+da_is_on()
+{
+	return (getdaon());
+}
+
+/*
+ * da_print_device -
+ *	debug routine to print device entries.
+ */
+void
+da_print_device(int flag, devlist_t *devlist)
+{
+	deventry_t	*entry, *dentry;
+	devinfo_t	*devinfo;
+
+	if (flag & DA_AUDIO)
+		dentry = devlist->audio;
+	else if (flag & DA_CD)
+		dentry = devlist->cd;
+	else if (flag & DA_FLOPPY)
+		dentry = devlist->floppy;
+	else if (flag & DA_TAPE)
+		dentry = devlist->tape;
+	else if (flag & DA_RMDISK)
+		dentry = devlist->rmdisk;
+	else
+		return;
+
+	for (entry = dentry; entry != NULL; entry = entry->next) {
+		devinfo = &(entry->devinfo);
+		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
+		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
+		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
+		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
+		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libbsm/common/devalloc.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_DEVALLOC_H
+#define	_DEVALLOC_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <secdb.h>
+
+/*
+ * These are unsupported, SUNWprivate interfaces.
+ */
+
+#define	DA_UID			(uid_t)0	/* root */
+#define	DA_GID			(gid_t)3	/* sys */
+#define	LOGINDEVPERM		"/etc/logindevperm"
+#define	DA_DB_LOCK		"/etc/security/.da_db_lock"
+#define	DA_DEV_LOCK		"/etc/security/.da_dev_lock"
+#define	DEVALLOC		"/etc/security/device_allocate"
+#define	DEVMAP			"/etc/security/device_maps"
+#define	DEFATTRS		"/etc/security/tsol/devalloc_defaults"
+#define	TMPALLOC		"/etc/security/.device_allocate"
+#define	TMPMAP			"/etc/security/.device_maps"
+#define	TMPATTRS		"/etc/security/tsol/.devalloc_defaults"
+
+#define	DA_DEFAULT_MIN		"admin_low"
+#define	DA_DEFAULT_MAX		"admin_high"
+#define	DA_DEFAULT_CLEAN	"/bin/true"
+#define	DA_DEFAULT_AUDIO_CLEAN	"/etc/security/lib/audio_clean_wrapper"
+#define	DA_DEFAULT_DISK_CLEAN	"/etc/security/lib/disk_clean"
+#define	DA_DEFAULT_TAPE_CLEAN	"/etc/security/lib/st_clean"
+
+#define	DA_ON_STR		"DEVICE_ALLOCATION=ON\n"
+#define	DA_OFF_STR		"DEVICE_ALLOCATION=OFF\n"
+#define	DA_IS_LABELED		"system_labeled"
+#define	DA_LABEL_CHECK		"/usr/bin/plabel"
+#define	DA_DBMODE		0644
+#define	DA_COUNT		5	/* allocatable devices suppported */
+					/* audio, cd, floppy, rmdisk, tape */
+#define	DA_AUTHLEN		MAX_CANON   /* approx. sum of strlen of all */
+					    /* device auths in auth_list.h */
+#define	DA_MAXNAME		80
+#define	DA_BUFSIZE		4096
+
+#define	DA_RDWR			O_RDWR|O_CREAT|O_NONBLOCK
+#define	DA_RDONLY		O_RDONLY|O_NONBLOCK
+
+#define	DA_ANYUSER		"*"
+#define	DA_NOUSER		"@"
+
+#define	ALLOC_UID	(uid_t)0	/* root */
+#define	ALLOC_GID	(gid_t)3	/* sys */
+#define	ALLOC_ERRID	(uid_t)2	/* bin */
+#define	ALLOC_MODE	0600
+#define	DEALLOC_MODE    0000
+
+#define	DA_SILENT		0x00000001
+#define	DA_VERBOSE		0x00000002
+#define	DA_ADD			0x00000004
+#define	DA_REMOVE		0x00000008
+#define	DA_UPDATE		0x00000010
+#define	DA_ADD_ZONE		0x00000020
+#define	DA_REMOVE_ZONE		0x00000040
+#define	DA_FORCE		0x00000080
+#define	DA_ALLOC_ONLY		0x00000100
+#define	DA_MAPS_ONLY		0x00000200
+#define	DA_ON			0x00000400
+#define	DA_OFF			0x00000800
+#define	DA_NO_OVERRIDE		0x00001000
+#define	DA_DEFATTRS		0x00002000
+
+#define	DA_AUDIO		0x00001000
+#define	DA_CD			0x00002000
+#define	DA_FLOPPY		0x00004000
+#define	DA_TAPE			0x00008000
+#define	DA_RMDISK		0x00010000
+
+#define	DA_AUDIO_NAME		"audio"
+#define	DA_SOUND_NAME		"sound"
+#define	DA_AUDIO_TYPE		DA_AUDIO_NAME
+#define	DA_AUDIO_DIR		"/dev/sound/"
+
+#define	DA_CD_NAME		"cdrom"
+#define	DA_CD_TYPE		"sr"
+
+#define	DA_DISK_DIR		"/dev/dsk/"
+#define	DA_DISK_DIRR		"/dev/rdsk/"
+#define	DA_DISKR_DIR		"/dev/(r)dsk"
+
+#define	DA_FLOPPY_NAME		"floppy"
+#define	DA_FLOPPY_TYPE		"fd"
+
+#define	DA_RMDISK_NAME		"rmdisk"
+#define	DA_RMDISK_TYPE		DA_RMDISK_NAME
+
+#define	DA_TAPE_NAME		"tape"
+#define	DA_TAPE_DIR		"/dev/rmt/"
+#define	DA_TAPE_TYPE		"st"
+
+typedef struct _devinfo_t {
+	char	*devname;
+	char	*devtype;
+	char	*devauths;
+	char	*devexec;
+	char	*devopts;
+	char	*devlist;
+	int	instance;
+} devinfo_t;
+
+typedef struct _deventry_t {
+	devinfo_t		devinfo;
+	struct _deventry_t	*next;
+} deventry_t;
+
+typedef struct _devlist_t {
+	deventry_t	*audio;
+	deventry_t	*cd;
+	deventry_t	*floppy;
+	deventry_t	*tape;
+	deventry_t	*rmdisk;
+} devlist_t;
+
+typedef struct _da_optargs {
+	int		optflag;
+	char		*rootdir;
+	char		**devnames;
+	devinfo_t	*devinfo;
+} da_args;
+
+typedef struct _da_defs {
+	char		*devtype;
+	kva_t		*devopts;
+} da_defs_t;
+
+da_defs_t *getdadefent(void);
+da_defs_t *getdadeftype(char *);
+void freedadefent(da_defs_t *);
+void setdadefent(void);
+void enddadefent(void);
+int da_is_on(void);
+int da_check_logindevperm(char *);
+int da_open_devdb(char *, FILE **, FILE **, int);
+int da_update_device(da_args *);
+int da_update_defattrs(da_args *);
+int da_add_list(devlist_t *, char *, int, int);
+int da_remove_list(devlist_t *, char *, int, char *, int);
+void da_print_device(int, devlist_t *);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _DEVALLOC_H */
--- a/usr/src/lib/libbsm/common/devices.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/devices.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,36 +32,55 @@
 extern "C" {
 #endif
 
-typedef struct {		/* see getdmapent(3) */
-	char *dmap_devname;
-	char *dmap_devtype;
-	char *dmap_devlist;
+#include <stdio.h>
+#include <secdb.h>
+
+/*
+ * These are unsupported, SUN-private interfaces.
+ */
+
+#define	DAOPT_AUTHS	"auths"
+#define	DAOPT_CSCRIPT	"cleanscript"
+#define	DAOPT_MINLABEL	"minlabel"
+#define	DAOPT_MAXLABEL	"maxlabel"
+#define	DAOPT_ZONE	"zone"
+#define	DA_RESERVED	"reserved"
+
+typedef struct {
+	char	*da_devname;
+	char	*da_devtype;
+	char	*da_devauth;
+	char	*da_devexec;
+	kva_t	*da_devopts;
+} devalloc_t;
+
+typedef struct {
+	char	*dmap_devname;
+	char	*dmap_devtype;
+	char	*dmap_devlist;
+	char	**dmap_devarray;
 } devmap_t;
 
-devmap_t *getdmapent(void);
-devmap_t *getdmaptype(char *);
-devmap_t *getdmapnam(char *);
-devmap_t *getdmapdev(char *);
-void setdmapent(void);
-void enddmapent(void);
-void setdmapfile(char *);
+int		getdadmline(char *, int, FILE *);
+
+devalloc_t	*getdaent(void);
+devalloc_t	*getdatype(char *);
+devalloc_t	*getdanam(char *);
+void		setdaent(void);
+void		enddaent(void);
+void		freedaent(devalloc_t *);
+void		setdafile(char *);
 
-typedef struct {		/* see getdaent(3) */
-	char *da_devname;
-	char *da_devtype;
-	char *da_devmin;
-	char *da_devmax;
-	char *da_devauth;
-	char *da_devexec;
-} devalloc_t;
-
-devalloc_t *getdaent(void);
-devalloc_t *getdatype(char *);
-devalloc_t *getdanam(char *);
-devalloc_t *getdadev(char *);
-void setdaent(void);
-void enddaent(void);
-void setdafile(char *);
+devmap_t	*getdmapent(void);
+devmap_t	*getdmaptype(char *);
+devmap_t	*getdmapnam(char *);
+devmap_t	*getdmapdev(char *);
+void		setdmapent(void);
+void		enddmapent(void);
+void		freedmapent(devmap_t *);
+void		setdmapfile(char *);
+char		*getdmapfield(char *);
+char		*getdmapdfield(char *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libbsm/common/generic.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/generic.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -37,6 +36,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <tsol/label.h>
 #include <bsm/audit.h>
 #include <bsm/libbsm.h>
 #include <bsm/audit_uevents.h>
@@ -426,6 +426,9 @@
 			(void) au_write(ad, au_to_newgroups(ng, grplst));
 		}
 	}
+	if (is_system_labeled())
+		(void) au_write(ad, au_to_mylabel());
+
 	if (aug_text != NULL) {
 		(void) au_write(ad, au_to_text(aug_text));
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libbsm/common/getdadefs.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,234 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <string.h>
+#include <stdlib.h>
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
+
+char *strtok_r(char *, const char *, char **);
+
+/* externs from getdaent.c */
+extern char *trim_white(char *);
+extern int pack_white(char *);
+extern char *getdadmfield(char *, char *);
+extern int getdadmline(char *, int, FILE *);
+
+extern char *_strdup_null(char *);
+
+static struct _dadefbuff {
+	FILE		*_dadeff;
+			/* pointer into /etc/security/tsol/devalloc_defaults */
+	da_defs_t	_interpdadefs;
+	char		_interpdadefline[DA_BUFSIZE + 1];
+	char		 *_DADEFS;
+} *__dadefbuff;
+
+#define	dadeff		(_df->_dadeff)
+#define	interpdadefs	(_df->_interpdadefs)
+#define	interpdadefline	(_df->_interpdadefline)
+#define	DADEFS_FILE	(_df->_DADEFS)
+
+static da_defs_t	*dadef_interpret(char *);
+int dadef_matchtype(da_defs_t *, char *);
+
+/*
+ * _dadefalloc -
+ *	allocates common buffers and structures.
+ * 	returns pointer to the new structure, else returns NULL on error.
+ */
+static struct _dadefbuff *
+_dadefalloc(void)
+{
+	struct _dadefbuff *_df = __dadefbuff;
+
+	if (_df == NULL) {
+		_df = (struct _dadefbuff *)calloc((unsigned)1,
+		    (unsigned)sizeof (*__dadefbuff));
+		if (_df == NULL)
+			return (NULL);
+		DADEFS_FILE = "/etc/security/tsol/devalloc_defaults";
+		__dadefbuff = _df;
+	}
+
+	return (__dadefbuff);
+}
+
+/*
+ * setdadefent -
+ *	rewinds devalloc_defaults file to the begining.
+ */
+
+void
+setdadefent(void)
+{
+	struct _dadefbuff *_df = _dadefalloc();
+
+	if (_df == NULL)
+		return;
+	if (dadeff == NULL)
+		dadeff = fopen(DADEFS_FILE, "r");
+	else
+		rewind(dadeff);
+}
+
+/*
+ * enddadefent -
+ *	closes devalloc_defaults file.
+ */
+
+void
+enddadefent(void)
+{
+	struct _dadefbuff *_df = _dadefalloc();
+
+	if (_df == NULL)
+		return;
+	if (dadeff != NULL) {
+		(void) fclose(dadeff);
+		dadeff = NULL;
+	}
+}
+
+void
+freedadefent(da_defs_t *da_def)
+{
+	if (da_def == NULL)
+		return;
+	_kva_free(da_def->devopts);
+	da_def->devopts = NULL;
+}
+
+/*
+ * getdadefent -
+ *	When first called, returns a pointer to the first da_defs_t
+ * 	structure in devalloc_defaults; thereafter, it returns a pointer to the
+ *	next da_defs_t structure in the file. Thus, successive calls can be
+ *	used to search the entire file.
+ *	call to getdadefent should be bracketed by setdadefent and enddadefent.
+ *	returns NULL on error.
+ */
+da_defs_t *
+getdadefent(void)
+{
+	char			line1[DA_BUFSIZE + 1];
+	da_defs_t		*da_def;
+	struct _dadefbuff	*_df = _dadefalloc();
+
+	if ((_df == 0) || (dadeff == NULL))
+		return (NULL);
+
+	while (getdadmline(line1, (int)sizeof (line1), dadeff) != 0) {
+		if ((da_def = dadef_interpret(line1)) == NULL)
+			continue;
+		return (da_def);
+	}
+
+	return (NULL);
+}
+
+/*
+ * getdadeftype -
+ * 	searches from the beginning of devalloc_defaults for the device
+ *	specified by its type.
+ *	call to getdadeftype should be bracketed by setdadefent and enddadefent.
+ * 	returns pointer to da_defs_t for the device if it is found, else
+ *	returns NULL if device not found or in case of error.
+ */
+da_defs_t *
+getdadeftype(char *type)
+{
+	char			line1[DA_BUFSIZE + 1];
+	da_defs_t		*da_def;
+	struct _dadefbuff	*_df = _dadefalloc();
+
+	if ((type == NULL) || (_df == NULL) || (dadeff == NULL))
+		return (NULL);
+
+	while (getdadmline(line1, (int)sizeof (line1), dadeff) != 0) {
+		if (strstr(line1, type) == NULL)
+			continue;
+		if ((da_def = dadef_interpret(line1)) == NULL)
+			continue;
+		if (dadef_matchtype(da_def, type))
+			return (da_def);
+		freedadefent(da_def);
+	}
+
+	return (NULL);
+}
+
+/*
+ * dadef_matchtype -
+ *	checks if the specified da_defs_t is for the device type specified.
+ *	returns 1 if match found, else, returns 0.
+ */
+int
+dadef_matchtype(da_defs_t *da_def, char *type)
+{
+	if (da_def->devtype == NULL)
+		return (0);
+
+	return ((strcmp(da_def->devtype, type) == 0));
+}
+
+/*
+ * dadef_interpret -
+ *	parses val and initializes pointers in da_defs_t.
+ * 	returns pointer to parsed da_defs_t entry, else returns NULL on error.
+ */
+static da_defs_t  *
+dadef_interpret(char *val)
+{
+	struct _dadefbuff	*_df = _dadefalloc();
+	int			i;
+	char			*opts;
+	kva_t			*kvap;
+	kv_t			*kvp;
+
+	if (_df == NULL)
+		return (NULL);
+
+	(void) strcpy(interpdadefline, val);
+	interpdadefs.devtype = getdadmfield(interpdadefline, KV_TOKEN_DELIMIT);
+	opts = getdadmfield(NULL, KV_TOKEN_DELIMIT);
+	interpdadefs.devopts = NULL;
+	if (interpdadefs.devtype == NULL)
+		return (NULL);
+	if (opts != NULL)
+		interpdadefs.devopts =
+		    _str2kva(opts, KV_ASSIGN, KV_DELIMITER);
+	/* remove any extraneous whitespace in the options */
+	if ((kvap = interpdadefs.devopts) != NULL) {
+		for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
+			(void) pack_white(kvp->key);
+			(void) pack_white(kvp->value);
+		}
+	}
+
+	return (&interpdadefs);
+}
--- a/usr/src/lib/libbsm/common/getdaent.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/getdaent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,320 +18,242 @@
  *
  * CDDL HEADER END
  */
-
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#include <stdio.h>
-#include <string.h>
-#include <malloc.h>
-#include <bsm/devices.h>
+#ifndef lint
+static char	sccsid[] = "%Z%%M% %I% %E% SMI";
+#endif
 
-#define	MAXINT 0x7fffffff;
-#ifdef SunOS_CMW
-extern char	*calloc();
-#endif
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <tsol/label.h>
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
+
+extern char *_strdup_null(char *);
 
 static struct _dabuff {
-	devalloc_t _NULLDA;
-	FILE *_daf;	/* pointer into /etc/security/device_allocate */
-	devalloc_t _interpdevalloc;
-	char _interpline[BUFSIZ + 1];
-	char *_DEVALLOC;
+	FILE		*_daf;	/* pointer into /etc/security/device_allocate */
+	devalloc_t	_interpdevalloc;
+	char		_interpdaline[DA_BUFSIZE + 1];
+	char		 *_DEVALLOC;
 } *__dabuff;
 
-#define	NULLDA (_da->_NULLDA)
-#define	daf (_da->_daf)
-#define	interpdevalloc (_da->_interpdevalloc)
-#define	interpline (_da->_interpline)
-#define	DEVALLOC (_da->_DEVALLOC)
-static devalloc_t  *interpret();
-static int matchname();
+#define	daf	(_da->_daf)
+#define	interpdevalloc	(_da->_interpdevalloc)
+#define	interpdaline	(_da->_interpdaline)
+#define	DEVALLOC_FILE	(_da->_DEVALLOC)
+static devalloc_t	*da_interpret(char *);
+
+int da_matchname(devalloc_t *, char *);
+int da_matchtype(devalloc_t *, char *);
+
+static int system_labeled = 0;
 
 /*
- * trim_white(ptr) trims off leading and trailing white space from a NULL
- * terminated string pointed to by "ptr". The leading white space is skipped
- * by moving the pointer forward. The trailing white space is removed by
- * nulling the white space characters.  The pointer is returned to the white
- * string. If the resulting string is null in length then a NULL pointer is
- * returned. If "ptr" is NULL then a NULL pointer is returned.
+ * trim_white -
+ *	trims off leading and trailing white space from input string.
+ * 	The leading white space is skipped by moving the pointer forward.
+ * 	The trailing white space is removed by nulling the white space
+ *	characters.
+ *	returns pointer to non-white string, else returns NULL if input string
+ *	is null or if the resulting string has zero length.
  */
-static char	*
-trim_white(ptr)
-char	*ptr;
+char *
+trim_white(char *ptr)
 {
-	register char	*tptr;
-	register int	cnt;
+	char	*tptr;
+
 	if (ptr == NULL)
 		return (NULL);
-	while ((*ptr == ' ') || (*ptr == '\t')) {
+	while (isspace(*ptr))
 		ptr++;
-	}
-	cnt = strlen(ptr);
-	if (cnt != 0) {
-		tptr = ptr + cnt - 1;
-		while ((*tptr == ' ') || (*tptr == '\t')) {
-			*tptr = '\0';
-			tptr--;
-		}
-	}
-	if (*ptr == NULL)
+	tptr = ptr + strlen(ptr);
+	while (tptr != ptr && isspace(tptr[-1]))
+		--tptr;
+	*tptr = '\0';
+	if (*ptr == '\0')
 		return (NULL);
+
 	return (ptr);
 }
 
-
 /*
- * scan string pointed to by pointer "p"
- * find next colin or end of line. Null it and
- * return pointer to next char.
+ * pack_white -
+ *	trims off multiple occurrences of white space from input string.
+ * 	returns the number of spaces retained
  */
-static char	*
-daskip(p)
-register char	*p;
+int
+pack_white(char *ptr)
 {
-	while (*p && *p != ';' && *p != '\n')
-		++p;
-	if (*p == '\n')
-		*p = '\0';
-	else if (*p != '\0')
-		*p++ = '\0';
-	return (p);
+	int	cnt = 0;
+	char	*tptr, ch;
+
+	if (ptr == NULL)
+		return (0);
+	tptr = ptr;
+	while (isspace(*tptr))
+		tptr++;
+	for (;;) {
+		while ((ch = *tptr) != '\0' && !isspace(ch)) {
+			*ptr++ = ch;
+			tptr++;
+		}
+		while (isspace(*tptr))
+			tptr++;
+		if (*tptr == '\0')
+			break;
+		*ptr++ = ' ';
+		cnt++;
+	}
+	*ptr = '\0';
+
+	return (cnt);
 }
 
-
-/*
- * scan string pointed to by pointer "p"
- * find next colin or end of line. Null it and
- * return pointer to next char.
- */
-static char	*
-dadskip(p)
-register char	*p;
-{
-	while (*p && *p != ' ' && *p != '\n')
-		++p;
-	if (*p != '\0')
-		*p++ = '\0';
-	return (p);
-}
-
-
 /*
- * _daalloc() allocates common buffers and structures used by the device
- * allocate library routines. Then returns a pointer to a structure.  The
- * returned pointer will be null if there is an error condition.
+ * getdadmline -
+ *	reads one device_alloc/device_maps line from stream into buff of len
+ *	bytes. Continued lines from stream are concatenated into one line in
+ *	buff. Comments are removed from buff.
+ *	returns the number of characters in buff, else returns 0 if no
+ * 	characters are read or an error occurred.
  */
-static struct _dabuff *
-_daalloc()
+int
+getdadmline(char *buff, int len, FILE *stream)
 {
-	register struct _dabuff *_da = __dabuff;
-
-	if (_da == 0) {
-		_da = (struct _dabuff *)
-		calloc((size_t)1, sizeof (*__dabuff));
-		if (_da == 0)
-			return (0);
-		DEVALLOC = "/etc/security/device_allocate";
-		__dabuff = _da;
-	}
-	return (__dabuff);
-}
-
+	int 	tmpcnt;
+	int 	charcnt = 0;
+	int 	fileerr = 0;
+	int 	contline = 0;
+	char 	*cp;
+	char 	*ccp;
 
-/*
- * getdaline(buff,len,stream) reads one device allocate line from "stream" into
- * "buff" on "len" bytes.  Continued lines from "stream" are concatinated
- * into one line in "buff". Comments are removed from "buff". The number of
- * characters in "buff" is returned.  If no characters are read or an err or
- * occured then "0" is returned
- */
-static int
-getdaline(buff, len, stream)
-	char *buff;
-	int len;
-	FILE *stream;
-{
-	register struct _dabuff *_da = _daalloc();
-	char	*cp;
-	char	*ccp;
-	int	tmpcnt;
-	int	charcnt = 0;
-	int	fileerr = 0;
-	int	contline;
-	if (_da == 0)
-		return (0);
 	do {
 		cp = buff;
 		*cp = NULL;
 		do {
+			contline = 0;
 			if (fgets(cp, len - charcnt, stream) == NULL) {
 				fileerr = 1;
 				break;
 			}
-			ccp = strpbrk(cp, "\\\n");
+			ccp = strchr(cp, '\n');
 			if (ccp != NULL) {
-				if (*ccp == '\\')
+				if (ccp != cp && ccp[-1] == '\\') {
+					ccp--;
 					contline = 1;
-					else
+				}
+				else
 					contline = 0;
 				*ccp = NULL;
 			}
 			tmpcnt = strlen(cp);
-			if (tmpcnt != 0) {
-				cp += tmpcnt;
-				charcnt += tmpcnt;
-			}
+			cp += tmpcnt;
+			charcnt += tmpcnt;
 		} while ((contline) || (charcnt == 0));
 		ccp = strpbrk(buff, "#");
 		if (ccp != NULL)
 			*ccp = NULL;
 		charcnt = strlen(buff);
 	} while ((fileerr == 0) && (charcnt == 0));
-	if (fileerr)
+
+	if (fileerr && !charcnt)
 		return (0);
-		else
+	else
 		return (charcnt);
 }
 
-char	*
-getdafield(ptr)
-char	*ptr;
+/*
+ * _daalloc -
+ *	allocates common buffers and structures.
+ * 	returns pointer to the new structure, else returns NULL on error.
+ */
+static struct _dabuff *
+_daalloc(void)
 {
-	static char	*tptr;
-	if (ptr == NULL)
-		ptr = tptr;
-	if (ptr == NULL)
-		return (NULL);
-	tptr = daskip(ptr);
-	ptr = trim_white(ptr);
-	if (ptr == NULL)
-		return (NULL);
-	if (*ptr == NULL)
-		return (NULL);
-	return (ptr);
-}
+	struct _dabuff	*_da = __dabuff;
 
-char	*
-getdadfield(ptr)
-char	*ptr;
-{
-	static char	*tptr;
-	if (ptr != NULL) {
-		ptr = trim_white(ptr);
-	} else {
-		ptr = tptr;
+	if (_da == NULL) {
+		_da = (struct _dabuff *)calloc((unsigned)1,
+		    (unsigned)sizeof (*__dabuff));
+		if (_da == NULL)
+			return (NULL);
+		DEVALLOC_FILE = "/etc/security/device_allocate";
+		daf = NULL;
+		__dabuff = _da;
+		system_labeled = is_system_labeled();
 	}
-	if (ptr == NULL)
-		return (NULL);
-	tptr = dadskip(ptr);
-	if (ptr == NULL)
-		return (NULL);
-	if (*ptr == NULL)
-		return (NULL);
-	return (ptr);
+
+	return (__dabuff);
 }
 
 /*
- * getdadev(dev) searches from the beginning of the file until a logical
- * device matching "dev" is found and returns a pointer to the particular
- * structure in which it was found.  If an EOF or an error is encountered on
- * reading, these functions return a NULL pointer.
+ * getdadmfield -
+ *	gets individual fields separated by skip in ptr.
  */
-#ifdef NOTDEF
-devalloc_t *
-getdadev(name)
-	register char	*name;
+char *
+getdadmfield(char *ptr, char *skip)
 {
-	register struct _dabuff *_da = _daalloc();
-	devalloc_t *da;
-	char	line[BUFSIZ + 1];
+	static char	*tptr = NULL;
+	char		*pend;
 
-	if (_da == 0)
-		return (0);
-	setdaent();
-	if (!daf)
-		return ((devalloc_t *)NULL);
-	while (getdaline(line, sizeof (line), daf) != 0) {
-		if ((da = interpret(line)) == NULL)
-			continue;
-		if (matchdev(&da, name)) {
-			enddaent();
-			return (da);
-		}
-	}
-	enddaent();
-	return ((devalloc_t *)NULL);
+	/* check for a continuing search */
+	if (ptr == NULL)
+		ptr = tptr;
+	/* check for source end */
+	if (ptr == NULL || *ptr == '\0')
+		return (NULL);
+	/* find terminator */
+	pend = strpbrk(ptr, skip);
+	/* terminate and set continuation pointer */
+	if (pend != NULL) {
+		*pend++ = '\0';
+		tptr = pend;
+	} else
+		tptr = NULL;
+	/*
+	 * trim off any surrounding white space, return what's left
+	 */
+
+	return (trim_white(ptr));
 }
 
-
-#endif /* NOTDEF */
-
 /*
- * getdanam(name) searches from the beginning of the file until a audit-name
- * matching "name" is found and returns a pointer to the particular structure
- * in which it was found.  If an EOF or an error is encountered on reading,
- * these functions return a NULL pointer.
- */
-devalloc_t *
-getdanam(name)
-	register char	*name;
-{
-	register struct _dabuff *_da = _daalloc();
-	devalloc_t *da;
-	char line[BUFSIZ + 1];
-
-	if (_da == 0)
-		return (0);
-	setdaent();
-	if (!daf)
-		return ((devalloc_t *)NULL);
-	while (getdaline(line, (int)sizeof (line), daf) != 0) {
-		if ((da = interpret(line)) == NULL)
-			continue;
-		if (matchname(&da, name)) {
-			enddaent();
-			return (da);
-		}
-	}
-	enddaent();
-	return ((devalloc_t *)NULL);
-}
-
-
-/*
- * setdaent() essentially rewinds the device_allocate file to the begining.
+ * setdaent -
+ *	rewinds the device_allocate file to the begining.
  */
 
 void
-setdaent()
+setdaent(void)
 {
-	register struct _dabuff *_da = _daalloc();
+	struct _dabuff	*_da = _daalloc();
 
-	if (_da == 0)
+	if (_da == NULL)
 		return;
-	if (daf == NULL) {
-		daf = fopen(DEVALLOC, "r");
-	} else
+	if (daf == NULL)
+		daf = fopen(DEVALLOC_FILE, "r");
+	else
 		rewind(daf);
 }
 
-
 /*
- * enddaent() may be called to close the device_allocate file when processing
- * is complete.
+ * enddaent -
+ *	closes device_allocate file.
  */
 
 void
-enddaent()
+enddaent(void)
 {
-	register struct _dabuff *_da = _daalloc();
+	struct _dabuff	*_da = _daalloc();
 
-	if (_da == 0)
+	if (_da == NULL)
 		return;
 	if (daf != NULL) {
 		(void) fclose(daf);
@@ -340,173 +261,294 @@
 	}
 }
 
-
 /*
- * setdafile(name) changes the default device_allocate file to "name" thus
- * allowing alternate device_allocate files to be used.  Note: it does not
- * close the previous file . If this is desired, enddaent should be called
- * prior to it.
+ * setdafile -
+ *	changes the default device_allocate file to the one specified.
+ * 	It does not close the previous file. If this is desired, enddaent
+ *	should be called prior to setdafile.
  */
 void
-setdafile(file)
-char	*file;
+setdafile(char *file)
 {
-	register struct _dabuff *_da = _daalloc();
+	struct _dabuff	*_da = _daalloc();
 
-	if (_da == 0)
+	if (_da == NULL)
 		return;
 	if (daf != NULL) {
 		(void) fclose(daf);
 		daf = NULL;
 	}
-	DEVALLOC = file;
+	DEVALLOC_FILE = file;
 }
 
+void
+freedaent(devalloc_t *dap)
+{
+	if (dap == NULL)
+		return;
+	_kva_free(dap->da_devopts);
+	dap->da_devopts = NULL;
+}
 
 /*
- * getdatype(tp) When first called, returns a pointer to the
- * first devalloc_t structure in the file with device-type matching
- * "tp"; thereafter, it returns a pointer to the next devalloc_t
- * structure in the file with device-type matching "tp".
- * Thus successive calls can be used to search the
- * entire file for entries having device-type matching "tp".
- * A null pointer is returned on error.
+ * getdaon -
+ *	checks if device_allocate has string DEVICE_ALLOCATION=ON or
+ *	DEVICE_ALLOCATION=OFF string in it.
+ *	returns 1 if the string is DEVICE_ALLOCATION=ON, 0 if it is
+ *	DEVICE_ALLOCATION=OFF, -1 if neither string present.
+ */
+int
+getdaon()
+{
+	int		is_on = -1;
+	char		line1[DA_BUFSIZE + 1];
+	struct _dabuff *_da = _daalloc();
+
+	setdaent();
+	if ((_da == NULL) || (daf == NULL)) {
+		enddaent();
+		return (is_on);
+	}
+	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
+		if (strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) {
+			is_on = 1;
+			break;
+		} else if (strncmp(line1, DA_OFF_STR,
+		    (strlen(DA_OFF_STR) - 1)) == 0) {
+			is_on = 0;
+			break;
+		}
+	}
+	enddaent();
+
+	return (is_on);
+}
+
+/*
+ * getdaent -
+ *	When first called, returns a pointer to the first devalloc_t
+ * 	structure in device_allocate; thereafter, it returns a pointer to the
+ *	next devalloc_t structure in the file. Thus, successive calls can be
+ *	used to search the entire file.
+ *	call to getdaent should be bracketed by setdaent and enddaent.
+ *	returns NULL on error.
  */
 devalloc_t *
-getdatype(tp)
-	char	*tp;
+getdaent(void)
 {
-	register struct _dabuff *_da = _daalloc();
-	char line1[BUFSIZ + 1];
-	devalloc_t *da;
+	char		line1[DA_BUFSIZE + 1];
+	devalloc_t	*da;
+	struct _dabuff	*_da = _daalloc();
+
+	if ((_da == 0) || (daf == NULL))
+		return (NULL);
 
-	if (_da == 0)
-		return (0);
-	if (daf == NULL && (daf = fopen(DEVALLOC, "r")) == NULL) {
-		return (NULL);
+	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
+		if ((strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) ||
+		    (strncmp(line1, DA_OFF_STR, (strlen(DA_OFF_STR) - 1)) == 0))
+			continue;
+		if ((da = da_interpret(line1)) == NULL)
+			continue;
+		return (da);
 	}
-	do {
-		if (getdaline(line1, (int)sizeof (line1), daf) == 0)
-			return (NULL);
 
-		if ((da = interpret(line1)) == NULL)
-			return (NULL);
-	} while (strcmp(tp, da->da_devtype) != 0);
-	return (da);
+	return (NULL);
 }
 
-
 /*
- * getdaent() When first called, returns a pointer to the first devalloc_t
- * structure in the file; thereafter, it returns a pointer to the next
- * devalloc_t structure in the file. Thus successive calls can be used to
- * search the entire file.  A null pointer is returned on error.
+ * getdanam
+ * 	searches from the beginning of device_allocate for the device specified
+ * 	by its name.
+ *	call to getdanam should be bracketed by setdaent and enddaent.
+ * 	returns pointer to devalloc_t for the device if it is found, else
+ *	returns NULL if device not found or in case of error.
  */
 devalloc_t *
-getdaent()
+getdanam(char *name)
 {
-	register struct _dabuff *_da = _daalloc();
-	char line1[BUFSIZ + 1];
-	devalloc_t *da;
+	char		line[DA_BUFSIZE + 1];
+	devalloc_t	*da;
+	struct _dabuff	*_da = _daalloc();
 
-	if (_da == 0)
-		return (0);
-	if (daf == NULL && (daf = fopen(DEVALLOC, "r")) == NULL) {
-		return (NULL);
-	}
-	if (getdaline(line1, (int)sizeof (line1), daf) == 0)
+	if ((name == NULL) || (_da == 0) || (daf == NULL))
 		return (NULL);
 
-	if ((da = interpret(line1)) == NULL)
-		return (NULL);
-	return (da);
+	while (getdadmline(line, (int)sizeof (line), daf) != 0) {
+		if (strstr(line, name) == NULL)
+			continue;
+		if ((da = da_interpret(line)) == NULL)
+			continue;
+		if (da_matchname(da, name)) {
+			enddaent();
+			return (da);
+		}
+		freedaent(da);
+	}
+
+	return (NULL);
 }
 
-
 /*
- * matchdev(dap,dev) The dev_list in the structure pointed to by "dap" is
- * searched for string "dev".  If a match occures then a "1" is returned
- * otherwise a "0" is returned.
+ * getdatype -
+ * 	searches from the beginning of device_allocate for the device specified
+ * 	by its type.
+ *	call to getdatype should be bracketed by setdaent and enddaent.
+ * 	returns pointer to devalloc_t for the device if it is found, else
+ *	returns NULL if device not found or in case of error.
  */
-#ifdef NOTDEF
-static
-matchdev(dap, dev)
-	devalloc_t **dap;
-	char	*dev;
+devalloc_t *
+getdatype(char *type)
 {
-	register struct _dabuff *_da = _daalloc();
-	devalloc_t *da = *dap;
-	char tmpdev[BUFSIZ + 1];
-	int	charcnt;
-	int	tmpcnt;
-	char	*cp;
-	char	*tcp;
-	char	*last;
+	char		line1[DA_BUFSIZE + 1];
+	devalloc_t	*da;
+	struct _dabuff	*_da = _daalloc();
+
+	if ((type == NULL) || (_da == NULL) || (daf == NULL))
+		return (NULL);
 
-	charcnt = strlen(dev);
-	if (_da == 0)
+	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
+		if (strstr(line1, type) == NULL)
+			continue;
+		if ((da = da_interpret(line1)) == NULL)
+			continue;
+		if (da_matchtype(da, type))
+			return (da);
+		freedaent(da);
+	}
+
+	return (NULL);
+}
+
+/*
+ * da_matchname -
+ *	checks if the specified devalloc_t is for the device specified.
+ * 	returns 1 if it is, else returns 0.
+ */
+int
+da_matchname(devalloc_t *dap, char *name)
+{
+	if (dap->da_devname == NULL)
 		return (0);
-	if (da->da_devlist == NULL)
+
+	return ((strcmp(dap->da_devname, name) == 0));
+}
+
+/*
+ * da_matchtype -
+ *	checks if the specified devalloc_t is for the device type specified.
+ *	returns 1 if match found, else, returns 0.
+ */
+int
+da_matchtype(devalloc_t *da, char *type)
+{
+	if (da->da_devtype == NULL)
 		return (0);
-	(void) strcpy(tmpdev, da->da_devlist);
-	tcp = tmpdev;
-	while ((cp = strtok_r(tcp, " ", &last)) != NULL) {
-		tcp = NULL;
-		tmpcnt = strlen(cp);
-		if (tmpcnt != charcnt)
-			continue;
-		if (strcmp(cp, dev) == 0)
-			return (1);
-	}
+
+	return ((strcmp(da->da_devtype, type) == 0));
+}
+
+/*
+ * da_match -
+ * 	calls da_matchname or da_matchdev as appropriate.
+ */
+int
+da_match(devalloc_t *dap, da_args *dargs)
+{
+	if (dargs->devinfo->devname)
+		return (da_matchname(dap, dargs->devinfo->devname));
+	else if (dargs->devinfo->devtype)
+		return (da_matchtype(dap, dargs->devinfo->devtype));
+
 	return (0);
 }
 
-#endif /* NOTDEF */
 /*
- * matchname(dap,name) The audit-name in the structure pointed to by "dap" is
- * searched for string "name".  If a match occures then a "1" is returned
- * otherwise a "0" is returned.
- */
-static int
-matchname(dap, name)
-	devalloc_t **dap;
-	char *name;
-{
-	register struct _dabuff *_da = _daalloc();
-	devalloc_t *da = *dap;
-
-	if (_da == 0)
-		return (0);
-	if (da->da_devname == NULL)
-		return (0);
-	if (strlen(da->da_devname) != strlen(name))
-		return (0);
-	if (strcmp(da->da_devname, name) == 0)
-		return (1);
-	return (0);
-}
-
-
-/*
- * interpret(val) string "val" is parsed and the pointers in a devalloc_t
- * structure are initialized to point to fields in "val". A pointer to this
- * structure is returned.
+ * da_interpret -
+ *	parses val and initializes pointers in devalloc_t.
+ * 	returns pointer to parsed devalloc_t entry, else returns NULL on error.
  */
 static devalloc_t  *
-interpret(val)
-char	*val;
+da_interpret(char *val)
 {
-	register struct _dabuff *_da = _daalloc();
+	struct _dabuff	*_da = _daalloc();
+	char	*opts;
+	int	i;
+	kva_t	*kvap;
+	kv_t	*kvp;
+
+	if (_da == NULL)
+		return (NULL);
+
+	(void) strcpy(interpdaline, val);
+	interpdevalloc.da_devname = getdadmfield(interpdaline, KV_DELIMITER);
+	interpdevalloc.da_devtype = getdadmfield(NULL, KV_DELIMITER);
+	opts = getdadmfield(NULL, KV_DELIMITER);
+	(void) getdadmfield(NULL, KV_DELIMITER);	/* reserved field */
+	interpdevalloc.da_devauth = getdadmfield(NULL, KV_DELIMITER);
+	interpdevalloc.da_devexec = getdadmfield(NULL, KV_DELIMITER);
+	interpdevalloc.da_devopts = NULL;
+	if (interpdevalloc.da_devname == NULL ||
+	    interpdevalloc.da_devtype == NULL)
+		return (NULL);
+	if ((opts != NULL) &&
+	    (strncmp(opts, DA_RESERVED, strlen(DA_RESERVED)) != 0)) {
+		interpdevalloc.da_devopts =
+		    _str2kva(opts, KV_ASSIGN, KV_TOKEN_DELIMIT);
+	}
+	/* remove any extraneous whitespace in the options */
+	if ((kvap = interpdevalloc.da_devopts) != NULL) {
+		for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
+			(void) pack_white(kvp->key);
+			(void) pack_white(kvp->value);
+		}
+	}
 
-	if (_da == 0)
-		return (0);
-	(void) strcpy(interpline, val);
-	interpdevalloc.da_devname = getdafield(interpline);
-	interpdevalloc.da_devtype = getdafield((char *)NULL);
-	interpdevalloc.da_devmin = getdafield((char *)NULL);
-	interpdevalloc.da_devmax = getdafield((char *)NULL);
-	interpdevalloc.da_devauth = getdafield((char *)NULL);
-	interpdevalloc.da_devexec = getdafield((char *)NULL);
+	if (system_labeled) {
+		/* if label range is not defined, use the default range. */
+		int		i = 0, nlen = 0;
+		char		*minstr = NULL, *maxstr = NULL;
+		kva_t		*nkvap = NULL;
+		kv_t		*ndata = NULL, *odata = NULL;
 
+		if (kvap == NULL) {
+			nlen = 2;	/* minlabel, maxlabel */
+		} else {
+			nlen += kvap->length;
+			if ((minstr = kva_match(kvap, DAOPT_MINLABEL)) == NULL)
+				nlen++;
+			if ((maxstr = kva_match(kvap, DAOPT_MAXLABEL)) == NULL)
+				nlen++;
+		}
+		if ((minstr != NULL) && (maxstr != NULL))
+			/*
+			 * label range provided; we don't need to construct
+			 * default range.
+			 */
+			goto out;
+		nkvap = _new_kva(nlen);
+		ndata = nkvap->data;
+		if (kvap != NULL) {
+			for (i = 0; i < kvap->length; i++) {
+				odata = kvap->data;
+				ndata[i].key = _strdup_null(odata[i].key);
+				ndata[i].value = _strdup_null(odata[i].value);
+				nkvap->length++;
+			}
+		}
+		if (minstr == NULL) {
+			ndata[i].key = strdup(DAOPT_MINLABEL);
+			ndata[i].value = strdup(DA_DEFAULT_MIN);
+			nkvap->length++;
+			i++;
+		}
+		if (maxstr == NULL) {
+			ndata[i].key = strdup(DAOPT_MAXLABEL);
+			ndata[i].value = strdup(DA_DEFAULT_MAX);
+			nkvap->length++;
+		}
+		interpdevalloc.da_devopts = nkvap;
+	}
+
+out:
 	return (&interpdevalloc);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libbsm/common/getdevicerange.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <tsol/label.h>
+#include <bsm/devices.h>
+
+
+/*
+ * getdevicerange
+ *	Gets the minimum and maximum labels within which the device can
+ *	be used. If label range is not specified for the device in
+ *	device_allocate, defaults to admin_low and admin_high.
+ *	Returns malloc'ed blrange pointer, or NULL on any error.
+ */
+blrange_t *
+getdevicerange(const char *dev)
+{
+	int		err;
+	char		*lstr;
+	devalloc_t	*da;
+	devmap_t	*dm;
+	blrange_t	*range;
+
+	errno = 0;
+	if ((range = malloc(sizeof (blrange_t))) == NULL)
+		return (NULL);
+	if ((range->lower_bound = blabel_alloc()) == NULL) {
+		free(range);
+		return (NULL);
+	}
+	if ((range->upper_bound = blabel_alloc()) == NULL) {
+		blabel_free(range->lower_bound);
+		free(range);
+		return (NULL);
+	}
+
+	/*
+	 * If an entry is found for the named device,
+	 * return its label range.
+	 */
+	setdaent();
+	if ((da = getdanam((char *)dev)) == NULL) {
+		setdmapent();
+		/* check for an actual device file */
+		if ((dm = getdmapdev((char *)dev)) != NULL) {
+			da = getdanam(dm->dmap_devname);
+			freedmapent(dm);
+		}
+		enddmapent();
+	}
+	enddaent();
+	if (da == NULL) {
+		bsllow(range->lower_bound);
+		bslhigh(range->upper_bound);
+	} else {
+		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
+		if (lstr == NULL) {
+			bsllow(range->lower_bound);
+		} else if (stobsl(lstr, range->lower_bound, NO_CORRECTION,
+		    &err) == 0) {
+			blabel_free(range->lower_bound);
+			blabel_free(range->upper_bound);
+			free(range);
+			errno = ENOTSUP;
+			return (NULL);
+		}
+		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
+		if (lstr == NULL) {
+			bslhigh(range->upper_bound);
+		} else if (stobsl(lstr, range->upper_bound, NO_CORRECTION,
+		    &err) == 0) {
+			blabel_free(range->lower_bound);
+			blabel_free(range->upper_bound);
+			free(range);
+			errno = ENOTSUP;
+			return (NULL);
+		}
+		freedaent(da);
+	}
+
+	return (range);
+}
--- a/usr/src/lib/libbsm/common/getdment.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/getdment.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,73 +19,423 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#include <stdio.h>
 #include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <bsm/devices.h>
-#include <sys/errno.h>
+#include <bsm/devalloc.h>
+
+char *strtok_r(char *, const char *, char **);
 
-#define	MAXINT 0x7fffffff;
+/* externs from getdaent.c */
+extern char *trim_white(char *);
+extern int pack_white(char *);
+extern char *getdadmfield(char *, char *);
+extern int getdadmline(char *, int, FILE *);
 
 static struct _dmapbuff {
-	devmap_t _NULLDM;
-	FILE *_dmapf;	/* pointer into /etc/security/device_maps */
-	devmap_t _interpdevmap;
-	char _interpline[BUFSIZ + 1];
-	char *_DEVMAP;
+	FILE		*_dmapf;	/* for /etc/security/device_maps */
+	devmap_t	_interpdevmap;
+	char		_interpdmline[DA_BUFSIZE + 1];
+	char		*_DEVMAP;
 } *__dmapbuff;
 
-#define	NULLDM (_dmap->_NULLDM)
-#define	dmapf (_dmap->_dmapf)
-#define	interpdevmap (_dmap->_interpdevmap)
-#define	interpline (_dmap->_interpline)
-#define	DEVMAP (_dmap->_DEVMAP)
-static devmap_t  *interpret();
-static int matchdev();
-static int matchname();
+#define	dmapf	(_dmap->_dmapf)
+#define	interpdevmap	(_dmap->_interpdevmap)
+#define	interpdmline	(_dmap->_interpdmline)
+#define	DEVMAPS_FILE	(_dmap->_DEVMAP)
+
+devmap_t	*dmap_interpret(char *, devmap_t *);
+static devmap_t	*dmap_interpretf(char *, devmap_t *);
+static devmap_t *dmap_dlexpand(devmap_t *);
+
+int	dmap_matchdev(devmap_t *, char *);
+int	dmap_matchname(devmap_t *, char *);
+
+
+/*
+ * _dmapalloc -
+ *	allocates common buffers and structures.
+ *	returns pointer to the new structure, else returns NULL on error.
+ */
+static struct _dmapbuff *
+_dmapalloc(void)
+{
+	struct _dmapbuff *_dmap = __dmapbuff;
+
+	if (_dmap == NULL) {
+		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
+		    (unsigned)sizeof (*__dmapbuff));
+		if (_dmap == NULL)
+			return (NULL);
+		DEVMAPS_FILE = "/etc/security/device_maps";
+		dmapf = NULL;
+		__dmapbuff = _dmap;
+	}
+
+	return (_dmap);
+}
+
+/*
+ * setdmapent -
+ *	rewinds the device_maps file to the beginning.
+ */
+void
+setdmapent(void)
+{
+	struct _dmapbuff *_dmap = _dmapalloc();
+
+	if (_dmap == NULL)
+		return;
+	if (dmapf == NULL)
+		dmapf = fopen(DEVMAPS_FILE, "r");
+	else
+		rewind(dmapf);
+}
+
+/*
+ * enddmapent -
+ *	closes device_maps file.
+ */
+void
+enddmapent(void)
+{
+	struct _dmapbuff *_dmap = _dmapalloc();
+
+	if (_dmap == NULL)
+		return;
+	if (dmapf != NULL) {
+		(void) fclose(dmapf);
+		dmapf = NULL;
+	}
+}
+
+void
+freedmapent(devmap_t *dmap)
+{
+	char	**darp;
+
+	if ((darp = dmap->dmap_devarray) != NULL) {
+		while (*darp != NULL)
+			free(*darp++);
+		free(dmap->dmap_devarray);
+		dmap->dmap_devarray = NULL;
+	}
+}
+
+/*
+ * setdmapfile -
+ *	changes the default device_maps file to the one specified.
+ *	It does not close the previous file. If this is desired, enddmapent
+ *	should be called prior to setdampfile.
+ */
+void
+setdmapfile(char *file)
+{
+	struct _dmapbuff *_dmap = _dmapalloc();
+
+	if (_dmap == NULL)
+		return;
+	if (dmapf != NULL) {
+		(void) fclose(dmapf);
+		dmapf = NULL;
+	}
+	DEVMAPS_FILE = file;
+}
+
+/*
+ * getdmapent -
+ * 	When first called, returns a pointer to the first devmap_t structure
+ * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
+ *	structure in the file. Thus successive calls can be used to read the
+ *	entire file.
+ *	call to getdmapent should be bracketed by setdmapent and enddmapent.
+ * 	returns pointer to devmap_t found, else returns NULL if no entry found
+ * 	or on error.
+ */
+devmap_t *
+getdmapent(void)
+{
+	devmap_t		*dmap;
+	struct _dmapbuff 	*_dmap = _dmapalloc();
+
+	if ((_dmap == 0) || (dmapf == NULL))
+		return (NULL);
+
+	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
+	    dmapf) != 0) {
+		if ((dmap = dmap_interpret(interpdmline,
+		    &interpdevmap)) == NULL)
+			continue;
+		return (dmap);
+	}
+
+	return (NULL);
+}
+
+/*
+ * getdmapnam -
+ *	searches from the beginning of device_maps for the device specified by
+ *	its name.
+ *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
+ * 	returns pointer to devmapt_t for the device if it is found, else
+ * 	returns NULL if device not found or in case of error.
+ */
+devmap_t *
+getdmapnam(char *name)
+{
+	devmap_t		*dmap;
+	struct _dmapbuff	*_dmap = _dmapalloc();
+
+	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
+		return (NULL);
+
+	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
+	    dmapf) != 0) {
+		if (strstr(interpdmline, name) == NULL)
+			continue;
+		if ((dmap = dmap_interpretf(interpdmline,
+		    &interpdevmap)) == NULL)
+			continue;
+		if (dmap_matchname(dmap, name)) {
+			if ((dmap = dmap_dlexpand(dmap)) == NULL)
+				continue;
+			enddmapent();
+			return (dmap);
+		}
+		freedmapent(dmap);
+	}
+
+	return (NULL);
+}
+
 /*
- * trim_white(ptr) trims off leading and trailing white space from a NULL
- * terminated string pointed to by "ptr". The leading white space is skipped
- * by moving the pointer forward. The trailing white space is removed by
- * nulling the white space characters.  The pointer is returned to the white
- * string. If the resulting string is null in length then a NULL pointer is
- * returned. If "ptr" is NULL then a NULL pointer is returned.
+ * getdmapdev -
+ *	searches from the beginning of device_maps for the device specified by
+ *	its logical name.
+ *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
+ * 	returns  pointer to the devmap_t for the device if device is found,
+ *	else returns NULL if device not found or on error.
+ */
+devmap_t *
+getdmapdev(char *dev)
+{
+	devmap_t		*dmap;
+	struct _dmapbuff	*_dmap = _dmapalloc();
+
+	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
+		return (NULL);
+
+	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
+	    dmapf) != 0) {
+		if ((dmap = dmap_interpret(interpdmline,
+		    &interpdevmap)) == NULL)
+			continue;
+		if (dmap_matchdev(dmap, dev)) {
+			enddmapent();
+			return (dmap);
+		}
+		freedmapent(dmap);
+	}
+
+	return (NULL);
+}
+
+/*
+ * getdmaptype -
+ *	searches from the beginning of device_maps for the device specified by
+ *	its type.
+ *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
+ * 	returns pointer to devmap_t found, else returns NULL if no entry found
+ * 	or on error.
+ */
+devmap_t *
+getdmaptype(char *type)
+{
+	devmap_t		*dmap;
+	struct _dmapbuff	*_dmap = _dmapalloc();
+
+	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
+		return (NULL);
+
+	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
+	    dmapf) != 0) {
+		if ((dmap = dmap_interpretf(interpdmline,
+		    &interpdevmap)) == NULL)
+			continue;
+		if (dmap->dmap_devtype != NULL &&
+		    strcmp(type, dmap->dmap_devtype) == 0) {
+			if ((dmap = dmap_dlexpand(dmap)) == NULL)
+				continue;
+			return (dmap);
+		}
+		freedmapent(dmap);
+	}
+
+	return (NULL);
+}
+
+/*
+ * dmap_matchdev -
+ * 	checks if the specified devmap_t is for the device specified.
+ *	returns 1 if it is, else returns 0.
+ */
+int
+dmap_matchdev(devmap_t *dmap, char *dev)
+{
+	char **dva;
+	char *dv;
+
+	if (dmap->dmap_devarray == NULL)
+		return (0);
+	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
+		if (strcmp(dv, dev) == 0)
+			return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * dmap_matchtype -
+ *	checks if the specified devmap_t is for the device specified.
+ *	returns 1 if it is, else returns 0.
+ */
+int
+dmap_matchtype(devmap_t *dmap, char *type)
+{
+	if ((dmap->dmap_devtype == NULL) || (type == NULL))
+		return (0);
+
+	return ((strcmp(dmap->dmap_devtype, type) == 0));
+}
+
+/*
+ * dmap_matchname -
+ * 	checks if the specified devmap_t is for the device specified.
+ * 	returns 1 if it is, else returns 0.
+ */
+int
+dmap_matchname(devmap_t *dmap, char *name)
+{
+	if (dmap->dmap_devname == NULL)
+		return (0);
+
+	return ((strcmp(dmap->dmap_devname, name) == 0));
+}
+
+/*
+ * dm_match -
+ *	calls dmap_matchname or dmap_matchtype as appropriate.
+ */
+int
+dm_match(devmap_t *dmap, da_args *dargs)
+{
+	if (dargs->devinfo->devname)
+		return (dmap_matchname(dmap, dargs->devinfo->devname));
+	else if (dargs->devinfo->devtype)
+		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
+
+	return (0);
+}
+
+/*
+ * dmap_interpret -
+ *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
+ *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
+ */
+devmap_t  *
+dmap_interpret(char *val, devmap_t *dm)
+{
+	if (dmap_interpretf(val, dm) == NULL)
+		return (NULL);
+
+	return (dmap_dlexpand(dm));
+}
+
+/*
+ * dmap_interpretf -
+ * 	parses string "val" and initializes pointers in the given devmap_t to
+ * 	fields in "val".
+ * 	returns pointer to updated devmap_t.
+ */
+static devmap_t  *
+dmap_interpretf(char *val, devmap_t *dm)
+{
+	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
+	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
+	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
+	dm->dmap_devarray = NULL;
+	if (dm->dmap_devname == NULL ||
+	    dm->dmap_devtype == NULL ||
+	    dm->dmap_devlist == NULL)
+		return (NULL);
+
+	return (dm);
+}
+
+/*
+ * dmap_dlexpand -
+ * 	expands dmap_devlist of the form `devlist_generate`
+ *	returns unexpanded form if there is no '\`' or in case of error.
+ */
+static devmap_t *
+dmap_dlexpand(devmap_t *dmp)
+{
+	char	tmplist[DA_BUFSIZE + 1];
+	char	*cp, *cpl, **darp;
+	int	count;
+	FILE	*expansion;
+
+	dmp->dmap_devarray = NULL;
+	if (dmp->dmap_devlist == NULL)
+		return (NULL);
+	if (*(dmp->dmap_devlist) != '`') {
+		(void) strcpy(tmplist, dmp->dmap_devlist);
+	} else {
+		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
+		if ((cp = strchr(tmplist, '`')) != NULL)
+			*cp = '\0';
+		if ((expansion = popen(tmplist, "r")) == NULL)
+			return (NULL);
+		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
+		(void) pclose(expansion);
+		tmplist[count] = '\0';
+	}
+
+	/* cleanup the list */
+	count = pack_white(tmplist);
+	dmp->dmap_devarray = darp =
+	    (char **)malloc((count + 2) * sizeof (char *));
+	if (darp == NULL)
+		return (NULL);
+	cp = tmplist;
+	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
+		*darp = strdup(cp);
+		if (*darp == NULL) {
+			freedmapent(dmp);
+			return (NULL);
+		}
+		darp++;
+		cp = NULL;
+	}
+	*darp = NULL;
+
+	return (dmp);
+}
+
+/*
+ * dmapskip -
+ * 	scans input string to find next colon or end of line.
+ *	returns pointer to next char.
  */
 static char *
-trim_white(char *ptr)
-{
-	register char  *tptr;
-	register int    cnt;
-	if (ptr == NULL)
-		return (NULL);
-	while ((*ptr == ' ') || (*ptr == '\t')) {
-		ptr++;
-	}
-	cnt = strlen(ptr);
-	if (cnt != 0) {
-		tptr = ptr + cnt - 1;
-		while ((*tptr == ' ') || (*tptr == '\t')) {
-			*tptr = '\0';
-			tptr--;
-		}
-	}
-	if (*ptr == NULL)
-		return (NULL);
-	return (ptr);
-}
-/*
- * scan string pointed to by pointer "p"
- * find next colin or end of line. Null it and
- * return pointer to next char.
- */
-static char *
-dmapskip(register char *p)
+dmapskip(char *p)
 {
 	while (*p && *p != ':' && *p != '\n')
 		++p;
@@ -94,99 +443,32 @@
 		*p = '\0';
 	else if (*p != '\0')
 		*p++ = '\0';
+
 	return (p);
 }
+
 /*
- * scan string pointed to by pointer "p"
- * find next colin or end of line. Null it and
- * return pointer to next char.
+ * dmapdskip -
+ * 	scans input string to find next space or end of line.
+ *	returns pointer to next char.
  */
 static char *
-dmapdskip(register char *p)
+dmapdskip(p)
+	register char *p;
 {
 	while (*p && *p != ' ' && *p != '\n')
 		++p;
 	if (*p != '\0')
 		*p++ = '\0';
+
 	return (p);
 }
 
-/*
- * _dmapalloc() allocates common buffers and structures used by the device
- * maps library routines. Then returns a pointer to a structure.  The
- * returned pointer will be null if there is an error condition.
- */
-static struct _dmapbuff *
-_dmapalloc(void)
-{
-	register struct _dmapbuff *_dmap = __dmapbuff;
-
-	if (_dmap == 0) {
-		_dmap = (struct _dmapbuff *)
-			calloc((unsigned)1, (unsigned)sizeof (*__dmapbuff));
-		if (_dmap == 0)
-			return (0);
-		DEVMAP = "/etc/security/device_maps";
-		__dmapbuff = _dmap;
-	}
-	return (__dmapbuff);
-}
-/*
- * getdmapline(buff,len,stream) reads one device maps line from "stream" into
- * "buff" on "len" bytes.  Continued lines from "stream" are concatinated
- * into one line in "buff". Comments are removed from "buff". The number of
- * characters in "buff" is returned.  If no characters are read or an error
- * occured then "0" is returned
- */
-static int
-getdmapline(char *buff, int len, FILE *stream)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	char *cp;
-	char *ccp;
-	size_t tmpcnt;
-	int charcnt = 0;
-	int fileerr = 0;
-	int contline;
-	if (_dmap == 0)
-		return (0);
-	do {
-		cp = buff;
-		*cp = NULL;
-		do {
-			if ((len - charcnt <= 1) ||
-			    (fgets(cp, len - charcnt, stream) == NULL)) {
-				fileerr = 1;
-				break;
-			}
-			ccp = strpbrk(cp, "\\\n");
-			if (ccp != NULL) {
-				if (*ccp == '\\')
-					contline = 1;
-				else
-					contline = 0;
-				*ccp = NULL;
-			}
-			tmpcnt = strlen(cp);
-			if (tmpcnt != 0) {
-				cp += tmpcnt;
-				charcnt += tmpcnt;
-			}
-		} while ((contline) || (charcnt == 0));
-		ccp = strpbrk(buff, "#");
-		if (ccp != NULL)
-			*ccp = NULL;
-		charcnt = strlen(buff);
-	} while ((fileerr == 0) && (charcnt == 0));
-	if (fileerr && !charcnt)
-		return (0);
-	else
-		return (charcnt);
-}
-char
-*getdmapfield(char *ptr)
+char *
+getdmapfield(char *ptr)
 {
 	static	char	*tptr;
+
 	if (ptr == NULL)
 		ptr = tptr;
 	if (ptr == NULL)
@@ -197,10 +479,12 @@
 		return (NULL);
 	if (*ptr == NULL)
 		return (NULL);
+
 	return (ptr);
 }
-char
-*getdmapdfield(char *ptr)
+
+char *
+getdmapdfield(char *ptr)
 {
 	static	char	*tptr;
 	if (ptr != NULL) {
@@ -215,251 +499,6 @@
 		return (NULL);
 	if (*ptr == NULL)
 		return (NULL);
+
 	return (ptr);
 }
-/*
- * getdmapdev(dev) searches from the beginning of the file until a logical
- * device matching "dev" is found and returns a pointer to the particular
- * structure in which it was found.  If an EOF or an error is encountered on
- * reading, these functions return a NULL pointer.
- */
-devmap_t *
-getdmapdev(register char  *name)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	devmap_t *dmap;
-	char line[BUFSIZ + 1];
-
-	if (_dmap == 0)
-		return (0);
-	setdmapent();
-	if (!dmapf)
-		return (NULL);
-	while (getdmapline(line, (int)sizeof (line), dmapf) != 0) {
-		if ((dmap = interpret(line)) == NULL)
-			continue;
-		if (matchdev(&dmap, name)) {
-			enddmapent();
-			return (dmap);
-		}
-	}
-	enddmapent();
-	return (NULL);
-}
-/*
- * getdmapnam(name) searches from the beginning of the file until a audit-name
- * matching "name" is found and returns a pointer to the particular structure
- * in which it was found.  If an EOF or an error is encountered on reading,
- * these functions return a NULL pointer.
- */
-devmap_t *
-getdmapnam(register char  *name)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	devmap_t *dmap;
-	char line[BUFSIZ + 1];
-
-	if (_dmap == 0)
-		return (0);
-	setdmapent();
-	if (!dmapf)
-		return (NULL);
-	while (getdmapline(line, (int)sizeof (line), dmapf) != 0) {
-		if ((dmap = interpret(line)) == NULL)
-			continue;
-		if (matchname(&dmap, name)) {
-			enddmapent();
-			return (dmap);
-		}
-	}
-	enddmapent();
-	return (NULL);
-}
-
-/*
- * setdmapent() essentially rewinds the device_maps file to the begining.
- */
-
-void
-setdmapent(void)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-
-
-	if (_dmap == 0)
-		return;
-
-	if (dmapf == NULL) {
-		dmapf = fopen(DEVMAP, "r");
-	} else
-		rewind(dmapf);
-}
-
-
-/*
- * enddmapent() may be called to close the device_maps file when processing
- * is complete.
- */
-
-void
-enddmapent(void)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-
-	if (_dmap == 0)
-		return;
-	if (dmapf != NULL) {
-		(void) fclose(dmapf);
-		dmapf = NULL;
-	}
-}
-
-
-/*
- * setdmapfile(name) changes the default device_maps file to "name" thus
- * allowing alternate device_maps files to be used.  Note: it does not
- * close the previous file . If this is desired, enddmapent should be called
- * prior to it.
- */
-void
-setdmapfile(char *file)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-
-	if (_dmap == 0)
-		return;
-	if (dmapf != NULL) {
-		(void) fclose(dmapf);
-		dmapf = NULL;
-	}
-	DEVMAP = file;
-}
-/*
- * getdmaptype(tp) When first called, returns a pointer to the
- * first devmap_t structure in the file with device-type matching
- * "tp"; thereafter, it returns a pointer to the next devmap_t
- * structure in the file with device-type matching "tp".
- * Thus successive calls can be used to search the
- * entire file for entries having device-type matching "tp".
- * A null pointer is returned on error.
- */
-devmap_t *
-getdmaptype(char *tp)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	char line1[BUFSIZ + 1];
-	devmap_t *dmap;
-
-	if (_dmap == 0)
-		return (0);
-	if (dmapf == NULL && (dmapf = fopen(DEVMAP, "r")) == NULL) {
-		return (NULL);
-	}
-	do {
-		if (getdmapline(line1, (int)sizeof (line1), dmapf) == 0)
-			return (NULL);
-
-		if ((dmap = interpret(line1)) == NULL)
-			return (NULL);
-	} while (strcmp(tp, dmap->dmap_devtype) != 0);
-	return (dmap);
-}
-
-/*
- * getdmapent() When first called, returns a pointer to the first devmap_t
- * structure in the file; thereafter, it returns a pointer to the next devmap_t
- * structure in the file. Thus successive calls can be used to search the
- * entire file.  A null pointer is returned on error.
- */
-devmap_t *
-getdmapent(void)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	char line1[BUFSIZ + 1];
-	devmap_t *dmap;
-
-	if (_dmap == 0)
-		return (0);
-	if (dmapf == NULL && (dmapf = fopen(DEVMAP, "r")) == NULL) {
-		return (NULL);
-	}
-	if (getdmapline(line1, (int)sizeof (line1), dmapf) == 0)
-		return (NULL);
-
-	if ((dmap = interpret(line1)) == NULL)
-		return (NULL);
-	return (dmap);
-}
-/*
- * matchdev(dmapp,dev) The dev_list in the structure pointed to by "dmapp" is
- * searched for string "dev".  If a match occures then a "1" is returned
- * otherwise a "0" is returned.
- */
-static int
-matchdev(devmap_t **dmapp, char *dev)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	devmap_t *dmap = *dmapp;
-	char tmpdev[BUFSIZ + 1];
-	int charcnt;
-	int tmpcnt;
-	char *cp;
-	char *tcp;
-	char *last;
-	charcnt = strlen(dev);
-	if (_dmap == 0)
-		return (0);
-	if (dmap->dmap_devlist == NULL)
-		return (0);
-	(void) strcpy(tmpdev, dmap->dmap_devlist);
-	tcp = tmpdev;
-	while ((cp = strtok_r(tcp, " ", &last)) != NULL) {
-		tcp = NULL;
-		tmpcnt = strlen(cp);
-		if (tmpcnt != charcnt)
-			continue;
-		if (strcmp(cp, dev) == 0)
-			return (1);
-	}
-	return (0);
-}
-/*
- * matchname(dmapp,name) The audit-name in the structure pointed to by "dmapp"
- * is searched for string "name".  If a match occures then a "1" is returned
- * otherwise a "0" is returned.
- */
-static int
-matchname(devmap_t **dmapp, char *name)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-	devmap_t *dmap = *dmapp;
-
-	if (_dmap == 0)
-		return (0);
-	if (dmap->dmap_devname == NULL)
-		return (0);
-	if (strlen(dmap->dmap_devname) != strlen(name))
-		return (0);
-	if (strcmp(dmap->dmap_devname, name) == 0)
-		return (1);
-	return (0);
-}
-/*
- * interpret(val) string "val" is parsed and the pointers in a devmap_t
- * structure are initialized to point to fields in "val". A pointer to this
- * structure is returned.
- */
-static devmap_t  *
-interpret(char *val)
-{
-	register struct _dmapbuff *_dmap = _dmapalloc();
-
-	if (_dmap == 0)
-		return (0);
-	(void) strcpy(interpline, val);
-	interpdevmap.dmap_devname = getdmapfield(interpline);
-	interpdevmap.dmap_devtype = getdmapfield((char *)NULL);
-	interpdevmap.dmap_devlist = getdmapfield((char *)NULL);
-
-	return (&interpdevmap);
-}
--- a/usr/src/lib/libbsm/common/llib-lbsm	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/common/llib-lbsm	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -23,12 +22,13 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <bsm/devices.h>
+#include <bsm/devalloc.h>
 #include <bsm/audit.h>
 #include <bsm/libbsm.h>
 #include <bsm/audit_record.h>
--- a/usr/src/lib/libbsm/mkhdr.sh	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/mkhdr.sh	Fri Mar 24 12:29:20 2006 -0800
@@ -3,9 +3,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -21,8 +20,12 @@
 # CDDL HEADER END
 #
 #
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
+
 # Automagically generate the audit_uevents.h header file.
 #
 DATABASE=audit_event.txt
@@ -30,8 +33,8 @@
 
 cat <<EOF > $HEADER_FILE
 /*
- * Copyright (c) 1993-2001, Sun Microsystems, Inc.
- * All Rights Reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef	_BSM_AUDIT_UEVENTS_H
@@ -57,12 +60,31 @@
 
 nawk -F: '{if ((NF == 4) && substr($1,0,1) != "#")
 		if ($1 >= 2048) {
-			printf("#define	%s	",$2)
-			if (length($2) < 8)
-				printf("	")
-			if (length($2) < 16)
-				printf("	")
-			printf("%s	/* =%s %s */\n",$1,$4,$3)
+			# compute total output line length first
+			tlen = length($2);
+			llen = 8 + tlen;
+			llen += 8 - (llen % 8);
+			if (llen < 32)
+				llen = 32;
+			llen += length($1);
+			llen += 8 - (llen % 8);
+			llen += 5 + length($4) + length($3) + 3;
+
+			# if line is too long, then print the comment first
+			if (llen > 80)
+				printf("/* =%s %s */\n", $4, $3);
+
+			printf("#define\t%s\t", $2)
+			if (tlen < 8)
+				printf("\t");
+			if (tlen < 16)
+				printf("\t")
+			printf("%s", $1);
+
+			if (llen > 80)
+				printf("\n");
+			else
+				printf("\t/* =%s %s */\n", $4, $3);
 		}
 	  }' \
 < $DATABASE >> $HEADER_FILE
--- a/usr/src/lib/libbsm/spec/Makefile.targ	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/spec/Makefile.targ	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,11 +17,13 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
 #
 # lib/libbsm/spec/Makefile.targ
 
@@ -36,6 +37,7 @@
 		audit.o			\
 		auditon.o		\
 		auditsvc.o		\
+		devalloc.o		\
 		exceptions.o		\
 		getacinfo.o		\
 		getauclassent.o		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libbsm/spec/devalloc.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,220 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libbsm/spec/devalloc.spec
+
+function	getdadmline
+include		<bsm/devices.h>
+declaration	int getdadmline(char *, int, FILE *)
+version		SUNWprivate_1.1
+end		
+
+function	getdmapdfield
+include		<bsm/devices.h>
+declaration	char *getdmapdfield(char *)
+version		SUNWprivate_1.1
+end		
+
+function	setdaent
+include		<bsm/devices.h>
+declaration	void setdaent(void)
+version		SUNWprivate_1.1
+end		
+
+function	enddaent
+include		<bsm/devices.h>
+declaration	void enddaent(void)
+version		SUNWprivate_1.1
+end		
+
+function	setdafile
+include		<bsm/devices.h>
+declaration	void setdafile(char *)
+version		SUNWprivate_1.1
+end		
+
+function	freedaent
+include		<bsm/devices.h>
+declaration	void freedaent(devalloc_t *)
+version		SUNWprivate_1.1
+end
+
+function	getdaent
+include		<bsm/devices.h>
+declaration	devalloc_t *getdaent(void)
+version		SUNWprivate_1.1
+end		
+
+function	getdanam
+include		<bsm/devices.h>
+declaration	devalloc_t *getdanam(char *)
+version		SUNWprivate_1.1
+end		
+
+function	getdatype
+include		<bsm/devices.h>
+declaration	devalloc_t *getdatype(char *)
+version		SUNWprivate_1.1
+end		
+
+function	setdmapent
+include		<bsm/devices.h>
+declaration	void setdmapent(void)
+version		SUNWprivate_1.1
+end		
+
+function	enddmapent
+include		<bsm/devices.h>
+declaration	void enddmapent(void)
+version		SUNWprivate_1.1
+end		
+
+function	setdmapfile
+include		<bsm/devices.h>
+declaration	void setdmapfile(char *)
+version		SUNWprivate_1.1
+end		
+
+function	freedmapent
+include		<bsm/devices.h>
+declaration	void freedmapent(devmap_t *)
+version		SUNWprivate_1.1
+end
+
+function	getdmapent
+include		<bsm/devices.h>
+declaration	devmap_t *getdmapent(void)
+version		SUNWprivate_1.1
+end		
+
+function	getdmapnam
+include		<bsm/devices.h>
+declaration	devmap_t *getdmapnam(char *)
+version		SUNWprivate_1.1
+end		
+
+function	getdmapdev
+include		<bsm/devices.h>
+declaration	devmap_t *getdmapdev(char *)
+version		SUNWprivate_1.1
+end		
+
+function	getdmaptype
+include		<bsm/devices.h>
+declaration	devmap_t *getdmaptype(char *)
+version		SUNWprivate_1.1
+end		
+
+function	getdmapfield
+include		<bsm/devices.h>
+declaration	char *getdmapfield(char *)
+version		SUNWprivate_1.1
+end		
+
+function	setdadefent
+include		<bsm/devalloc.h>
+declaration	void setdadefent(void)
+version		SUNWprivate_1.1
+end		
+
+function	enddadefent
+include		<bsm/devalloc.h>
+declaration	void enddadefent(void)
+version		SUNWprivate_1.1
+end		
+
+function	freedadefent
+include		<bsm/devalloc.h>
+declaration	void freedadefent(da_defs_t *)
+version		SUNWprivate_1.1
+end
+
+function	getdadefent
+include		<bsm/devalloc.h>
+declaration	da_defs_t *getdadefent(void)
+version		SUNWprivate_1.1
+end		
+
+function	getdadeftype
+include		<bsm/devalloc.h>
+declaration	da_defs_t *getdadeftype(char *)
+version		SUNWprivate_1.1
+end		
+
+function	da_is_on
+include		<bsm/devalloc.h>
+declaration	int da_is_on(void)
+version		SUNWprivate_1.1
+end
+
+function	da_check_logindevperm
+include		<bsm/devalloc.h>
+declaration	int da_check_logindevperm(char *)
+version		SUNWprivate_1.1
+end
+
+function	da_open_devdb
+include		<bsm/devalloc.h>
+declaration	int da_open_devdb(char *, FILE **, FILE **, int)
+version		SUNWprivate_1.1
+end
+
+function	da_update_device
+include		<bsm/devalloc.h>
+declaration	int da_update_device(da_args *)
+version		SUNWprivate_1.1
+end
+
+function	da_update_defattrs
+include		<bsm/devalloc.h>
+declaration	int da_update_defattrs(da_args *)
+version		SUNWprivate_1.1
+end
+
+function	da_add_list
+include		<bsm/devalloc.h>
+declaration	int da_add_list(devlist_t *, char *, int, int)
+version		SUNWprivate_1.1
+end
+
+function	da_remove_list
+include		<bsm/devalloc.h>
+declaration	int da_remove_list(devlist_t *, char *, int, char *, int)
+version		SUNWprivate_1.1
+end
+
+function	da_print_device
+include		<bsm/devalloc.h>
+declaration	void da_print_device(int, devlist_t *)
+version		SUNWprivate_1.1
+end
+
+function	getdevicerange
+include		<sys/tsol/label.h> <bsm/devices.h>
+declaration	int getdevicerange(const char *, brange_t *);
+version		SUNWprivate_1.1
+end
--- a/usr/src/lib/libbsm/spec/private.spec	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libbsm/spec/private.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -242,6 +242,18 @@
 version		SUNWprivate_1.1
 end		
 
+function	au_to_mylabel
+include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
+declaration	token_t *au_to_mylabel(void)
+version		SUNWprivate_1.1
+end		
+
+function	au_to_label
+include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
+declaration	token_t *au_to_label(bslabel_t *label)
+version		SUNWprivate_1.1
+end		
+
 function	audit_allocate_argv
 include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
 declaration	int audit_allocate_argv(int flg, int argc, char *argv[])
@@ -644,18 +656,6 @@
 version		SUNWprivate_1.1
 end		
 
-function	enddaent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void enddaent(void)
-version		SUNWprivate_1.1
-end		
-
-function	enddmapent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void enddmapent(void)
-version		SUNWprivate_1.1
-end		
-
 function	_openac
 include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>
 declaration	au_acinfo_t *_openac(char *)
@@ -704,96 +704,6 @@
 version		SUNWprivate_1.1
 end		
 
-function	getdadfield
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	char *getdadfield(char *ptr)
-version		SUNWprivate_1.1
-end		
-
-function	getdaent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devalloc_t *getdaent(void)
-version		SUNWprivate_1.1
-end		
-
-function	getdafield
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	char *getdafield(char *ptr)
-version		SUNWprivate_1.1
-end		
-
-function	getdanam
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devalloc_t *getdanam(char *name)
-version		SUNWprivate_1.1
-end		
-
-function	getdatype
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devalloc_t *getdatype(char *tp)
-version		SUNWprivate_1.1
-end		
-
-function	getdmapdev
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devmap_t *getdmapdev(char *name)
-version		SUNWprivate_1.1
-end		
-
-function	getdmapdfield
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	char *getdmapdfield(char *ptr)
-version		SUNWprivate_1.1
-end		
-
-function	getdmapent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devmap_t *getdmapent(void)
-version		SUNWprivate_1.1
-end		
-
-function	getdmapfield
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	char *getdmapfield(char *ptr)
-version		SUNWprivate_1.1
-end		
-
-function	getdmapnam
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devmap_t *getdmapnam(char *name)
-version		SUNWprivate_1.1
-end		
-
-function	getdmaptype
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	devmap_t *getdmaptype(char *tp)
-version		SUNWprivate_1.1
-end		
-
-function	setdaent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void setdaent(void)
-version		SUNWprivate_1.1
-end		
-
-function	setdafile
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void setdafile(char *file)
-version		SUNWprivate_1.1
-end		
-
-function	setdmapent
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void setdmapent(void)
-version		SUNWprivate_1.1
-end		
-
-function	setdmapfile
-include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
-declaration	void setdmapfile(char *file)
-version		SUNWprivate_1.1
-end		
-
 function	audit_at_create
 include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
 version		SUNWprivate_1.1
@@ -1124,3 +1034,15 @@
                         ENXIO EPERM EWOULDBLOCK
 exception       $return == -1
 end
+
+function	au_to_privset
+include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
+declaration	token_t *au_to_privset(const char *priv_type, const priv_set_t *privilege)
+version		SUNWprivate_1.1
+end
+
+function	au_to_uauth
+include		<sys/types.h>, <bsm/audit.h>, <bsm/libbsm.h>, <bsm/audit_record.h>, <bsm/devices.h>, <pwd.h>
+declaration	token_t *au_to_uauth(char *text)
+version		SUNWprivate_1.1
+end
--- a/usr/src/lib/libc/amd64/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/amd64/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -772,6 +772,7 @@
 	getpeerucred.o		\
 	inst_sync.o		\
 	issetugid.o		\
+	label.o			\
 	libc_link.o		\
 	libc_open.o		\
 	lockf.o			\
--- a/usr/src/lib/libc/i386/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/i386/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -811,6 +811,7 @@
 	getpeerucred.o		\
 	inst_sync.o		\
 	issetugid.o		\
+	label.o			\
 	libc_link.o		\
 	libc_open.o		\
 	lockf.o			\
--- a/usr/src/lib/libc/inc/synonyms.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/inc/synonyms.h	Fri Mar 24 12:29:20 2006 -0800
@@ -481,6 +481,7 @@
 #define	isphonogram		_isphonogram
 #define	issetugid		_issetugid
 #define	isspecial		_isspecial
+#define	is_system_labeled	_is_system_labeled
 #define	iswalnum		_iswalnum
 #define	iswalpha		_iswalpha
 #define	iswcntrl		_iswcntrl
@@ -1039,6 +1040,7 @@
 #define	ucred_getegid		_ucred_getegid
 #define	ucred_geteuid		_ucred_geteuid
 #define	ucred_getgroups		_ucred_getgroups
+#define	ucred_getlabel		_ucred_getlabel
 #define	ucred_getpflags		_ucred_getpflags
 #define	ucred_getpid		_ucred_getpid
 #define	ucred_getprivset	_ucred_getprivset
--- a/usr/src/lib/libc/port/gen/ucred.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/port/gen/ucred.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -43,6 +42,7 @@
 #pragma weak ucred_getauid = _ucred_getauid
 #pragma weak ucred_getasid = _ucred_getasid
 #pragma weak ucred_getatid = _ucred_getatid
+#pragma weak ucred_getlabel = _ucred_getlabel
 #pragma weak ucred_getamask = _ucred_getamask
 #pragma weak ucred_size	 = _ucred_size
 
@@ -66,6 +66,7 @@
 #include <sys/procfs.h>
 #include <sys/sysmacros.h>
 #include <sys/zone.h>
+#include <tsol/label.h>
 
 ucred_t *
 _ucred_alloc(void)
@@ -260,6 +261,20 @@
 	return (uc->uc_zoneid);
 }
 
+bslabel_t *
+ucred_getlabel(const ucred_t *uc)
+{
+	/* LINTED: alignment */
+	bslabel_t *slabel = UCLABEL(uc);
+
+	if (!is_system_labeled() || slabel == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	return (slabel);
+}
+
 /*
  * For now, assume single bit flags.
  */
--- a/usr/src/lib/libc/port/llib-lc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/port/llib-lc	Fri Mar 24 12:29:20 2006 -0800
@@ -1740,3 +1740,6 @@
 
 /* private interface to unmount all autofs mounts */
 int _autofssys(enum autofssys_op, void *);
+
+/* label.c */
+extern int is_system_labeled(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libc/port/sys/label.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#pragma weak is_system_labeled = _is_system_labeled
+
+#include "synonyms.h"
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/tsol/tsyscall.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "libc.h"
+
+static	int	_is_labeled = -1;
+
+/*
+ * is_system_labeled :
+ *	Return the status of MAC labeling on this system.
+ *	Returns 0 if labeling is not installed or not active,
+ */
+int
+is_system_labeled(void)
+{
+	if (_is_labeled >= 0)
+		return (_is_labeled);		/* fast path if cached */
+
+	return (_is_labeled = syscall(SYS_labelsys, TSOL_SYSLABELING));
+}
--- a/usr/src/lib/libc/port/sys/zone.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/port/sys/zone.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,14 +36,15 @@
 #include <sys/priv.h>
 #include <priv_private.h>
 #include <zone.h>
+#include <sys/tsol/label.h>
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <errno.h>
 
-extern zoneid_t
+zoneid_t
 zone_create(const char *name, const char *root, const struct priv_set *privs,
     const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz,
-    int *extended_error)
+    int *extended_error, int match, int doi, const bslabel_t *label)
 {
 	zone_def  zd;
 	priv_data_t *d;
@@ -60,6 +60,9 @@
 	zd.zfsbuf = zfs;
 	zd.zfsbufsz = zfssz;
 	zd.extended_error = extended_error;
+	zd.match = match;
+	zd.doi = doi;
+	zd.label = label;
 
 	return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd));
 }
--- a/usr/src/lib/libc/sparc/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/sparc/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -836,6 +836,7 @@
 	getpeerucred.o		\
 	inst_sync.o		\
 	issetugid.o		\
+	label.o			\
 	libc_link.o		\
 	libc_open.o		\
 	lockf.o			\
--- a/usr/src/lib/libc/sparcv9/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/sparcv9/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -781,6 +781,7 @@
 	getpeerucred.o		\
 	inst_sync.o		\
 	issetugid.o		\
+	label.o			\
 	libc_link.o		\
 	libc_open.o		\
 	lockf.o			\
--- a/usr/src/lib/libc/spec/gen.spec	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/spec/gen.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -4698,6 +4698,17 @@
 version		SUNW_1.22
 end
 
+function	ucred_getlabel
+include		<ucred.h>
+declaration	bslabel_t *ucred_getlabel(const ucred_t *) 
+version		SUNW_1.22.2
+end
+
+function	_ucred_getlabel
+weak		ucred_getlabel
+version		SUNW_1.22.2
+end
+
 function	ucred_getpflags
 include		<ucred.h>
 declaration	uint_t ucred_getpflags(const ucred_t *, uint_t)
--- a/usr/src/lib/libc/spec/sys.spec	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/spec/sys.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,12 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -3432,9 +3431,11 @@
 
 function	zone_create
 include		<zone.h>
-declaration	zoneid_t zone_create(const char *zone_name, \
-		    const char *zone_root, const priv_set_t *zone_privs, \
-		    const char *rctlbuf, size_t rctlbufsz, int *)
+declaration	zoneid_t zone_create(const char *name, const char *root, \
+		    const struct priv_set *privs, const char *rctls, \
+		    size_t rctlsz, const char *zfs, size_t zfssz, \
+		    int *extended_error, int match, \
+		    int doi, const bslabel_t *label)
 version		SUNWprivate_1.1
 exception	$return == -1
 end
@@ -3519,3 +3520,13 @@
 weak		getzonenamebyid
 version		SUNWprivate_1.1
 end
+
+function	is_system_labeled
+declaration	int is_system_labeled(void)
+version		SUNW_1.22.2
+end
+
+function	_is_system_labeled
+weak		is_system_labeled
+version		SUNWprivate_1.1
+end
--- a/usr/src/lib/libc/spec/versions	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libc/spec/versions	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,12 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -26,6 +25,7 @@
 #
 
 i386 {
+	SUNW_1.22.2:	{SUNW_1.22.1};
 	SUNW_1.22.1:	{SUNW_1.22};
 	SUNW_1.22:	{SUNW_1.21.3};
 	SUNW_1.21.3:	{SUNW_1.21.2};
@@ -62,6 +62,7 @@
 	SUNWprivate_1.1;
 }
 amd64 {
+	SUNW_1.22.2:	{SUNW_1.22.1};
 	SUNW_1.22.1:	{SUNW_1.22};
 	SUNW_1.22:	{SUNW_1.21.3};
 	SUNW_1.21.3:	{SUNW_1.21.2};
@@ -98,6 +99,7 @@
 	SUNWprivate_1.1;
 }
 sparc {
+	SUNW_1.22.2:	{SUNW_1.22.1};
 	SUNW_1.22.1:	{SUNW_1.22};
 	SUNW_1.22:	{SUNW_1.21.3};
 	SUNW_1.21.3:	{SUNW_1.21.2};
@@ -135,6 +137,7 @@
 	SUNWprivate_1.1;
 }
 sparcv9 {
+	SUNW_1.22.2:	{SUNW_1.22.1};
 	SUNW_1.22.1:	{SUNW_1.22};
 	SUNW_1.22:	{SUNW_1.21.3};
 	SUNW_1.21.3:	{SUNW_1.21.2};
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,9 +44,11 @@
 #include <err.h>
 #include <net/pfpolicy.h>
 
+#ifndef A_CNT
 /* macros for array manipulation */
 #define	A_CNT(arr)	(sizeof (arr)/sizeof (arr[0]))
 #define	A_END(arr)	(&arr[A_CNT(arr)])
+#endif
 
 /* used for file parsing */
 #define	NBUF_SIZE	16
--- a/usr/src/lib/libldap5/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libldap5/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,25 @@
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -68,7 +88,7 @@
 LIBS =		$(DYNLIB) $(LINTLIB)
 DYNFLAGS +=	$(ZNODELETE)
 
-CPPFLAGS +=	-I$(COM_INC)
+CPPFLAGS=	$(COM_INC) $(CPPFLAGS.master)
 
 # definitions for lint
 
--- a/usr/src/lib/libnsl/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -27,7 +28,7 @@
 #
 # lib/libnsl/Makefile
 #
-PROTOCOL_DIR= $(ROOT)/usr/include/rpcsvc
+PROTOCOL_DIR= $(ROOTHDRDIR)/rpcsvc
 PROTOCOL_SRCDIR= $(SRC)/head/rpcsvc
 PROTOCOL_UTS_SRCDIR= $(SRC)/uts/common/rpc
 
@@ -71,9 +72,9 @@
 # include library definitions
 include ../Makefile.lib
 
-SED=	sed
-CP=	cp
-GREP=	grep
+# header file delivered to /usr/include; internal to ON build process
+HDRS =		nss.h
+HDRDIR =	nss
 
 LIBRARY= libnsl.a
 TEXT_DOMAIN= SUNW_OST_NETRPC
@@ -99,6 +100,11 @@
 
 install:	all $(SUBDIRS)
 
+install_h:	$(ROOTHDRS)
+
+# nss.h isn't delivered; no reason to check
+check:
+
 clean clobber delete lint package:	$(SUBDIRS)
 
 $(PROTOCOL_DIR):
--- a/usr/src/lib/libnsl/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -190,7 +191,8 @@
 # then use the environment variable LD_OPTIONS=-Dgot,detail to have the
 # linker print out the list of GOT hogs..
 
-GOTHOGS =	dial.o print_obj.o clnt_perror.o
+GOTHOGS =	dial.o print_obj.o clnt_perror.o nsl_stdio_prv.o netdir.o \
+		algs.o netselect.o
 BIGPICS =	$(GOTHOGS:%=pics/%)
 $(BIGPICS) :=	sparc_C_PICFLAGS = $(C_BIGPICFLAGS)
 $(BIGPICS) :=	i386_C_PICFLAGS = $(C_BIGPICFLAGS)
--- a/usr/src/lib/libnsl/nss/nss.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/nss/nss.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -64,6 +63,14 @@
 extern void	order_haddrlist_af(sa_family_t, char **);
 extern int	nss_ioctl(int, int, void *);
 
+/* parse.c */
+extern char *_strtok_escape(char *, char *, char **);
+extern char *_strpbrk_escape(char *, char *);
+extern char *_escape(char *, char *);
+extern char *_unescape(char *, char *);
+extern char *_strdup_null(char *);
+extern int _readbufline(char *,	int, char *, int, int *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/libnsl/rpc/clnt_bcast.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/clnt_bcast.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -43,6 +42,7 @@
  */
 
 #include "mt.h"
+#include "rpc_mt.h"
 #include <string.h>
 #include <strings.h>
 #include <rpc/rpc.h>
@@ -51,8 +51,6 @@
 #include <netdir.h>
 #ifdef PORTMAP
 #include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
-#include <rpc/pmap_rmt.h>
 #endif
 #ifdef RPC_DEBUG
 #include <stdio.h>
@@ -187,11 +185,13 @@
 			stat = RPC_CANTSEND;
 			continue;
 		}
+		__rpc_set_mac_options(fd, nconf, prog);
 		if (t_bind(fd, NULL, NULL) == -1) {
 			(void) t_close(fd);
 			stat = RPC_CANTSEND;
 			continue;
 		}
+
 		/* Do protocol specific negotiating for broadcast */
 		if (netdir_options(nconf, ND_SET_BROADCAST, fd, NULL)) {
 			(void) t_close(fd);
--- a/usr/src/lib/libnsl/rpc/clnt_generic.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/clnt_generic.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -403,6 +402,8 @@
 		if (fd < __rpc_minfd)
 			fd = __rpc_raise_fd(fd);
 
+		__rpc_set_mac_options(fd, nconf, prog);
+
 		/* LINTED pointer cast */
 		if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
 		    == NULL) {
@@ -622,6 +623,7 @@
 		if (fd < __rpc_minfd)
 			fd = __rpc_raise_fd(fd);
 		madefd = TRUE;
+		__rpc_set_mac_options(fd, nconf, prog);
 		if (t_bind(fd, NULL, NULL) == -1)
 			goto err;
 		switch (nconf->nc_semantics) {
--- a/usr/src/lib/libnsl/rpc/rpc_mt.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/rpc_mt.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -36,6 +35,7 @@
 
 #include <sys/types.h>
 #include <rpc/rpc.h>
+#include <netconfig.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -94,6 +94,8 @@
 extern void	__getpublickey_flush(const char *);
 extern int	__can_use_af(sa_family_t);
 extern int	__rpc_raise_fd(int);
+extern void	__rpc_set_mac_options(int, const struct netconfig *,
+	rpcprog_t);
 extern void	__tli_sys_strerror(char *, size_t, int, int);
 
 #ifdef	__cplusplus
--- a/usr/src/lib/libnsl/rpc/svc_dg.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/svc_dg.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -44,6 +43,7 @@
 #include "rpc_mt.h"
 #include <stdio.h>
 #include <sys/types.h>
+#include <sys/sysmacros.h>
 #include <rpc/rpc.h>
 #include <errno.h>
 #include <syslog.h>
@@ -284,6 +284,37 @@
 	return (XPRT_IDLE);
 }
 
+/*
+ * Find the SCM_UCRED in src and place a pointer to that option alone in dest.
+ * Note that these two 'netbuf' structures might be the same one, so the code
+ * has to be careful about referring to src after changing dest.
+ */
+static void
+extract_cred(const struct netbuf *src, struct netbuf *dest)
+{
+	char *cp = src->buf;
+	unsigned int len = src->len;
+	const struct T_opthdr *opt;
+	unsigned int olen;
+
+	while (len >= sizeof (*opt)) {
+		/* LINTED: pointer alignment */
+		opt = (const struct T_opthdr *)cp;
+		olen = opt->len;
+		if (olen > len || olen < sizeof (*opt) ||
+		    !IS_P2ALIGNED(olen, sizeof (t_uscalar_t)))
+			break;
+		if (opt->level == SOL_SOCKET && opt->name == SCM_UCRED) {
+			dest->buf = cp;
+			dest->len = olen;
+			return;
+		}
+		cp += olen;
+		len -= olen;
+	}
+	dest->len = 0;
+}
+
 static bool_t
 svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg)
 {
@@ -354,9 +385,10 @@
 			/* tu_data.addr is already set */
 			tu_data->udata.buf = reply;
 			tu_data->udata.len = (uint_t)replylen;
-			tu_data->opt.len = 0;
+			extract_cred(&tu_data->opt, &tu_data->opt);
 			(void) t_sndudata(xprt->xp_fd, tu_data);
 			tu_data->udata.buf = (char *)rpc_buffer(xprt);
+			tu_data->opt.buf = (char *)su->opts;
 			return (FALSE);
 		}
 	}
@@ -425,7 +457,7 @@
 
 		slen = (int)XDR_GETPOS(xdrs);
 		tu_data->udata.len = slen;
-		tu_data->opt.len = 0;
+		extract_cred(&su->optbuf, &tu_data->opt);
 try_again:
 		if (t_sndudata(xprt->xp_fd, tu_data) == 0) {
 			stat = TRUE;
@@ -440,6 +472,7 @@
 			"svc_dg_reply: t_sndudata error t_errno=%d errno=%d\n",
 				t_errno, errno);
 		}
+		tu_data->opt.buf = (char *)su->opts;
 	}
 	return (stat);
 }
--- a/usr/src/lib/libnsl/rpc/svc_generic.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/svc_generic.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,7 +51,14 @@
 #include <malloc.h>
 #include <string.h>
 #include <stropts.h>
-
+#include <tsol/label.h>
+#include <nfs/nfs.h>
+#include <nfs/nfs_acl.h>
+#include <rpcsvc/mount.h>
+#include <rpcsvc/nsm_addr.h>
+#include <rpcsvc/rquota.h>
+#include <rpcsvc/sm_inter.h>
+#include <rpcsvc/nlm_prot.h>
 
 extern int __svc_vc_setflag(SVCXPRT *, int);
 
@@ -80,6 +86,22 @@
 SVCXPRT_LIST *_svc_xprtlist = NULL;
 extern mutex_t xprtlist_lock;
 
+static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
+    const struct t_bind *, uint_t, uint_t, boolean_t);
+
+boolean_t
+is_multilevel(rpcprog_t prognum)
+{
+	/* This is a list of identified multilevel service provider */
+	if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
+	    (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
+	    (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
+	    (prognum == SM_PROG))
+		return (B_TRUE);
+
+	return (B_FALSE);
+}
+
 void
 __svc_free_xprtlist(void)
 {
@@ -162,6 +184,7 @@
 			const rpcvers_t versnum, const struct netconfig *nconf)
 {
 	SVCXPRT *xprt;
+	boolean_t anon_mlp = B_FALSE;
 
 	if (nconf == NULL) {
 		(void) syslog(LOG_ERR,
@@ -169,7 +192,11 @@
 				prognum, versnum);
 		return (NULL);
 	}
-	xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
+
+	/* Some programs need to allocate MLP for multilevel services */
+	if (is_system_labeled() && is_multilevel(prognum))
+		anon_mlp = B_TRUE;
+	xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);
 	if (xprt == NULL)
 		return (NULL);
 	(void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
@@ -183,6 +210,13 @@
 	return (xprt);
 }
 
+SVCXPRT *
+svc_tli_create(const int fd, const struct netconfig *nconf,
+    const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
+{
+	return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
+}
+
 /*
  * If fd is RPC_ANYFD, then it opens a fd for the given transport
  * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
@@ -193,8 +227,9 @@
  * If sendsz or recvsz are zero, their default values are chosen.
  */
 SVCXPRT *
-svc_tli_create(const int ofd, const struct netconfig *nconf,
-	const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
+svc_tli_create_common(const int ofd, const struct netconfig *nconf,
+	const struct t_bind *bindaddr, const uint_t sendsz,
+	const uint_t recvsz, boolean_t mlp_flag)
 {
 	SVCXPRT *xprt = NULL;		/* service handle */
 	struct t_info tinfo;		/* transport info */
@@ -293,6 +328,17 @@
 	switch (state) {
 		bool_t tcp, exclbind;
 	case T_UNBND:
+		/* If this is a labeled system, then ask for an MLP */
+		if (is_system_labeled() &&
+		    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+		    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+			(void) __rpc_tli_set_options(fd, SOL_SOCKET,
+			    SO_RECVUCRED, 1);
+			if (mlp_flag)
+				(void) __rpc_tli_set_options(fd, SOL_SOCKET,
+				    SO_ANON_MLP, 1);
+		}
+
 		/*
 		 * {TCP,UDP}_EXCLBIND has the following properties
 		 *    - an fd bound to port P via IPv4 will prevent an IPv6
--- a/usr/src/lib/libnsl/rpc/ti_opts.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libnsl/rpc/ti_opts.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -59,11 +58,10 @@
 #include <alloca.h>
 #include <stdlib.h>
 #include <zone.h>
+#include <tsol/label.h>
 
-extern const char *inet_ntop(int, const void *, char *, socklen_t);
 extern bool_t __svc_get_door_ucred(const SVCXPRT *, ucred_t *);
 
-
 /*
  * This routine is typically called on the server side if the server
  * wants to know the caller ucred.  Called typically by rpcbind.  It
@@ -494,6 +492,8 @@
 	case SO_REUSEADDR:
 	case SO_DGRAM_ERRIND:
 	case SO_RECVUCRED:
+	case SO_ANON_MLP:
+	case SO_MAC_EXEMPT:
 	case TCP_EXCLBIND:
 	case UDP_EXCLBIND:
 		/* LINTED */
@@ -548,3 +548,34 @@
 		(void) strlcpy(buf, errorstr, buflen);
 	}
 }
+
+/*
+ * Depending on the specified RPC number, attempt to set mac_exempt
+ * option on the opened socket; these requests need to be able to do MAC
+ * MAC read-down operations.  Privilege is needed to set this option.
+ */
+
+void
+__rpc_set_mac_options(int fd, const struct netconfig *nconf, rpcprog_t prognum)
+{
+	int ret = 0;
+
+	if (!is_system_labeled())
+		return;
+
+	if (strcmp(nconf->nc_protofmly, NC_INET) != 0 &&
+	    strcmp(nconf->nc_protofmly, NC_INET6) != 0)
+		return;
+
+	if (is_multilevel(prognum)) {
+		ret = __rpc_tli_set_options(fd, SOL_SOCKET, SO_MAC_EXEMPT, 1);
+		if (ret < 0) {
+			char errorstr[100];
+
+			__tli_sys_strerror(errorstr, sizeof (errorstr),
+			    t_errno, errno);
+			(void) syslog(LOG_ERR, "rpc_set_mac_options: %s",
+			    errorstr);
+		}
+	}
+}
--- a/usr/src/lib/libsldap/common/ns_common.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libsldap/common/ns_common.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -82,6 +81,8 @@
 	{ "profile",	"ou=profile,",		NULL },
 	{ "printers",	"ou=printers,",		NULL },
 	{ "automount",	"",			NULL },
+	{ "tnrhtp",	"ou=ipTnet,",		NULL },
+	{ "tnrhdb",	"ou=ipTnet,",		"tnrhtp" },
 	{ NULL, NULL, NULL }
 };
 
--- a/usr/src/lib/libsldap/common/ns_sldap.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libsldap/common/ns_sldap.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -450,6 +449,8 @@
 #define	NS_LDAP_TYPE_AUUSER	"audit_user"
 #define	NS_LDAP_TYPE_BOOTPARAMS "bootparams"
 #define	NS_LDAP_TYPE_AUTOMOUNT  "auto_"
+#define	NS_LDAP_TYPE_TNRHDB	"tnrhdb"
+#define	NS_LDAP_TYPE_TNRHTP	"tnrhtp"
 
 /*
  * service descriptor/attribute mapping structure
--- a/usr/src/lib/libsldap/common/ns_writes.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libsldap/common/ns_writes.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,6 +55,8 @@
 #include <prof_attr.h>
 #include <user_attr.h>
 #include <bsm/libbsm.h>
+#include <sys/tsol/tndb.h>
+#include <tsol/label.h>
 
 
 /*
@@ -3246,7 +3247,128 @@
 
 	return (NS_LDAP_SUCCESS);
 }
-
+/*
+ * Conversion:			tnrhtp
+ * Input format:		tsol_tpstr_t
+ * Exported objectclass:	ipTnetTemplate
+ */
+static int
+__s_cvt_tnrhtp(const void *data, char **rdn,
+	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
+{
+	ns_ldap_entry_t	*e;
+	int		rc;
+	char		trdn[RDNSIZE];
+	/* routine specific */
+	int		max_attr = 2;
+	tsol_tpstr_t	*ptr;
+	static		char *oclist[] = {
+			"ipTnetTemplate",
+			"top",
+			NULL
+			};
+
+	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
+		return (NS_LDAP_OP_FAILED);
+
+	*entry = e = __s_mk_entry(oclist, max_attr);
+	if (e == NULL)
+		return (NS_LDAP_MEMORY);
+
+	/* Convert the structure */
+	ptr = (tsol_tpstr_t *)data;
+
+	if ((ptr->template == NULL) || (strlen(ptr->template) <= 1)) {
+		__ns_ldap_freeEntry(e);
+		*entry = NULL;
+		return (NS_LDAP_INVALID_PARAM);
+	}
+
+	/* Create an appropriate rdn */
+	(void) snprintf(trdn, RDNSIZE, "ipTnetTemplateName=%s", ptr->template);
+	*rdn = strdup(trdn);
+	if (*rdn == NULL) {
+		__ns_ldap_freeEntry(e);
+		*entry = NULL;
+		return (NS_LDAP_MEMORY);
+	}
+
+	rc = __s_add_attr(e, "ipTnetTemplateName", ptr->template);
+	if (rc != NS_LDAP_SUCCESS) {
+		__s_cvt_freeEntryRdn(entry, rdn);
+		return (rc);
+	}
+
+	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attrs);
+	if (rc != NS_LDAP_SUCCESS) {
+		__s_cvt_freeEntryRdn(entry, rdn);
+		return (rc);
+	}
+
+	return (NS_LDAP_SUCCESS);
+}
+/*
+ * Conversion:			tnrhdb
+ * Input format:		tsol_rhstr_t
+ * Exported objectclass:	ipTnetHost
+ */
+static int
+__s_cvt_tnrhdb(const void *data, char **rdn,
+	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
+{
+	ns_ldap_entry_t	*e;
+	int		rc;
+	char		trdn[RDNSIZE];
+	/* routine specific */
+	tsol_rhstr_t	*ptr;
+	int		max_attr = 2;
+	static		char *oclist[] = {
+			"ipTnetHost",
+			"ipTnetTemplate",
+			"top",
+			NULL
+			};
+
+	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
+		return (NS_LDAP_OP_FAILED);
+
+	*entry = e = __s_mk_entry(oclist, max_attr);
+	if (e == NULL)
+		return (NS_LDAP_MEMORY);
+
+	/* Convert the structure */
+	ptr = (tsol_rhstr_t *)data;
+
+	if ((ptr->address == NULL) || (strlen(ptr->address) <= 1) ||
+	    (ptr->template == NULL) || (strlen(ptr->template) <= 1)) {
+		__ns_ldap_freeEntry(e);
+		*entry = NULL;
+		return (NS_LDAP_INVALID_PARAM);
+	}
+
+	/* Create an appropriate rdn */
+	(void) snprintf(trdn, RDNSIZE, "ipTnetNumber=%s", ptr->address);
+	*rdn = strdup(trdn);
+	if (*rdn == NULL) {
+		__ns_ldap_freeEntry(e);
+		*entry = NULL;
+		return (NS_LDAP_MEMORY);
+	}
+
+	rc = __s_add_attr(e, "ipTnetNumber", ptr->address);
+	if (rc != NS_LDAP_SUCCESS) {
+		__s_cvt_freeEntryRdn(entry, rdn);
+		return (rc);
+	}
+
+	rc = __s_add_attr(e, "ipTnetTemplateName", ptr->template);
+	if (rc != NS_LDAP_SUCCESS) {
+		__s_cvt_freeEntryRdn(entry, rdn);
+		return (rc);
+	}
+
+	return (NS_LDAP_SUCCESS);
+}
 /*
  * Add Typed Entry Conversion data structures
  */
@@ -3283,6 +3405,8 @@
 	{ NS_LDAP_TYPE_AUTOMOUNT,	0, __s_cvt_auto_mount },
 	{ NS_LDAP_TYPE_PUBLICKEY,	AE, __s_cvt_publickey },
 	{ NS_LDAP_TYPE_AUUSER,		AE, __s_cvt_audituser },
+	{ NS_LDAP_TYPE_TNRHTP,		0,  __s_cvt_tnrhtp },
+	{ NS_LDAP_TYPE_TNRHDB,		0,  __s_cvt_tnrhdb },
 	{ NULL,				0, NULL },
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.lib
+
+HDRS =		libtsnet.h
+HDRDIR =	common
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all	:= TARGET= all
+clean	:= TARGET= clean
+clobber	:= TARGET= clobber
+install	:= TARGET= install
+lint	:= TARGET= lint
+
+POFILE =	libtsnet.po
+MSGFILES =	common/misc.i
+
+.KEEP_STATE:
+
+all install: spec .WAIT $(SUBDIRS)
+
+clean clobber: spec $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(POFILE): $(MSGFILES)
+	$(BUILDPO.msgfiles)
+
+spec $(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+LIBRARY	=	libtsnet.a
+VERS =		.1
+
+OBJECTS = \
+	misc.o \
+	tnrh.o tnrhtp.o tnmlp.o \
+	tsol_getrhent.o tsol_gettpent.o \
+	tsol_sgetrhent.o tsol_sgettpent.o tsol_sgetzcent.o
+
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+$(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
+
+LAZYLIBS =	$(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+LDLIBS +=	-lsocket -lnsl -lc -lsecdb $(LAZYLIBS)
+lint :=		LAZYLIBS = -ltsol
+
+SRCDIR =	../common
+MAPDIR =	../spec/$(TRANSMACH)
+SPECMAPFILE =	$(MAPDIR)/mapfile
+
+LIBTSOLINC =	$(SRC)/lib/libtsol/common
+
+CPPFLAGS +=	-D_REENTRANT -I$(LIBTSOLINC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/amd64/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/libtsnet.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * All symbols and functions in this header file and library are private to Sun
+ * Microsystems.  The only guarantee that is made is that if your application
+ * uses them, it will break on upgrade.
+ */
+
+#ifndef	_LIBTSNET_H
+#define	_LIBTSNET_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <sys/tsol/tndb.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	TNRHTP_PATH	"/etc/security/tsol/tnrhtp"
+#define	TNRHDB_PATH	"/etc/security/tsol/tnrhdb"
+#define	TNZONECFG_PATH	"/etc/security/tsol/tnzonecfg"
+
+#define	TNDB_COMMA	", \t"
+
+/*
+ * String parsing routines
+ *
+ * These functions are in four logical groups: one for template (tnrhtp)
+ * entries, one for remote host (tnrhdb) entries, one for zone configuration
+ * (tnzonecfg) entries, and a fourth for routing attributes.
+ *
+ * In each group, there are functions that parse from a string or database, and
+ * a function to free returned entries.  The parsing functions all take a
+ * pointer to an integer and a pointer to a character pointer for returning
+ * errors.  On error, the returned entry pointer is NULL, the integer is set to
+ * one of the LTSNET_* errors below, and the character pointer points to the
+ * location of the error.  (For the functions that iterate on a database, this
+ * points into static storage in the library.  This storage is associated with
+ * the iterator.)
+ *
+ * The functions that do look-ups based on a value (name or address) do not
+ * return errors other than "not found," which is signaled by a return value of
+ * NULL.
+ */
+
+/* Template entry parsing */
+extern tsol_tpent_t *tsol_gettpbyname(const char *);
+extern tsol_tpent_t *tsol_gettpent(void);
+extern tsol_tpent_t *tsol_fgettpent(FILE *);
+extern void tsol_freetpent(tsol_tpent_t *);
+extern void tsol_settpent(int);
+extern void tsol_endtpent(void);
+extern int str_to_tpstr(const char *, int, void *, char *, int);
+extern tsol_tpent_t *tpstr_to_ent(tsol_tpstr_t *, int *, char **);
+
+/* Remote host entry parsing */
+extern tsol_rhent_t *tsol_getrhbyaddr(const void *, size_t, int);
+extern tsol_rhent_t *tsol_getrhent(void);
+extern tsol_rhent_t *tsol_fgetrhent(FILE *);
+extern void tsol_freerhent(tsol_rhent_t *);
+extern void tsol_setrhent(int);
+extern void tsol_endrhent(void);
+extern int str_to_rhstr(const char *, int, void *, char *, int);
+extern tsol_rhent_t *rhstr_to_ent(tsol_rhstr_t *, int *, char **);
+extern tsol_host_type_t tsol_getrhtype(char *);
+
+
+/* Zone configuration parsing */
+extern tsol_zcent_t *tsol_sgetzcent(const char *, int *, char **);
+extern void tsol_freezcent(tsol_zcent_t *);
+
+/* Routing attribute parsing */
+extern const char *sl_to_str(const bslabel_t *);
+struct rtsa_s;
+extern const char *rtsa_to_str(const struct rtsa_s *, char *, size_t);
+extern boolean_t rtsa_keyword(const char *, struct rtsa_s *, int *, char **);
+extern const char *parse_entry(char *, size_t, const char *, const char *);
+
+/* Convert LTSNET_* to a printable string */
+extern const char *tsol_strerror(int, int);
+
+/* System calls; these return -1 on error and set errno */
+extern int tnrhtp(int, tsol_tpent_t *);
+extern int tnrh(int, tsol_rhent_t *);
+extern int tnmlp(int, tsol_mlpent_t *);
+
+/*
+ * Errors that can occur in the parsing routines.  Note that not all errors are
+ * possible with every routine.  Must be kept in sync with list in misc.c.
+ */
+#define	LTSNET_NONE		0	/* No error */
+#define	LTSNET_SYSERR		1	/* System error; see errno */
+#define	LTSNET_EMPTY		2	/* Empty string or end of list */
+#define	LTSNET_ILL_ENTRY	3	/* Entry is malformed */
+#define	LTSNET_NO_NAME		4	/* Missing name */
+#define	LTSNET_NO_ATTRS		5	/* Missing template attributes */
+#define	LTSNET_ILL_NAME		6	/* Illegal name */
+#define	LTSNET_ILL_KEYDELIM	7	/* Illegal keyword delimiter */
+#define	LTSNET_ILL_KEY		8	/* Unknown keyword */
+#define	LTSNET_DUP_KEY		9	/* Duplicate keyword */
+#define	LTSNET_ILL_VALDELIM	10	/* Illegal value delimiter */
+#define	LTSNET_NO_HOSTTYPE	11	/* Missing host type */
+#define	LTSNET_ILL_HOSTTYPE	12	/* Illegal host type */
+#define	LTSNET_NO_LABEL		13	/* Missing label */
+#define	LTSNET_ILL_LABEL	14	/* Illegal label */
+#define	LTSNET_NO_RANGE		15	/* Missing label range */
+#define	LTSNET_ILL_RANGE	16	/* Illegal label range */
+#define	LTSNET_NO_LOWERBOUND	17	/* No lower bound in range */
+#define	LTSNET_ILL_LOWERBOUND	18	/* Illegal lower bound in range */
+#define	LTSNET_NO_UPPERBOUND	19	/* No upper bound in range */
+#define	LTSNET_ILL_UPPERBOUND	20	/* Illegal upper bound in range */
+#define	LTSNET_NO_DOI		21	/* Missing DOI */
+#define	LTSNET_ILL_DOI		22	/* Illegal DOI */
+#define	LTSNET_SET_TOO_BIG	23	/* Too many entries in set */
+#define	LTSNET_NO_ADDR		24	/* Missing address/network */
+#define	LTSNET_ILL_ADDR		25	/* Illegal address/network */
+#define	LTSNET_ILL_FLAG		26	/* Illegal flag */
+#define	LTSNET_ILL_MLP		27	/* Illegal MLP specification */
+#define	LTSNET_BAD_TYPE		28	/* Unacceptable keyword for type */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBTSNET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/llib-ltsnet	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libtsnet.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/misc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,359 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From "misc.c	5.15	00/05/31 SMI; TSOL 2.x"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	Miscellaneous user interfaces to trusted label functions.
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <libintl.h>
+#include <libtsnet.h>
+#include <tsol/label.h>
+
+#include <net/route.h>
+
+#define	MAX_STRING_SIZE 256
+#define	MAX_ATTR_LEN	1024
+
+/*
+ * Parse off an entry from a line.  Entry is stored in 'outbuf'.  Returned
+ * value is a pointer to the first unprocessed input character from 'instr'.
+ */
+const char *
+parse_entry(char *outbuf, size_t outlen, const char *instr,
+    const char *delimit)
+{
+	boolean_t escape_state = B_FALSE;
+	boolean_t any_white;
+	char chr;
+
+	any_white = strchr(delimit, '\n') != NULL;
+
+	/*
+	 * User may specify outlen as 0 to skip over a field without storing
+	 * it anywhere.  Otherwise, we need at least one byte for the
+	 * terminating NUL plus one byte to store another byte from instr.
+	 */
+	while (outlen != 1 && (chr = *instr++) != '\0') {
+		if (!escape_state) {
+			if (chr == '\\') {
+				escape_state = B_TRUE;
+				continue;
+			}
+			if (strchr(delimit, chr) != NULL)
+				break;
+			if (any_white && isspace(chr))
+				break;
+		}
+		escape_state = B_FALSE;
+		if (outlen > 0) {
+			*outbuf++ = chr;
+			outlen--;
+		}
+	}
+	if (outlen != 1)
+		instr--;
+	if (escape_state)
+		instr--;
+	if (outlen > 0)
+		*outbuf = '\0';
+	return (instr);
+}
+
+const char *
+sl_to_str(const bslabel_t *sl)
+{
+	const char *sl_str;
+	static const char unknown_str[] = "UNKNOWN";
+
+	if (sl == NULL)
+		return (unknown_str);
+
+	if ((sl_str = sbsltos(sl, MAX_STRING_SIZE)) == NULL &&
+	    (sl_str = bsltoh(sl)) == NULL)
+		sl_str = unknown_str;
+	return (sl_str);
+}
+
+static const char *rtsa_keywords[] = {
+#define	SAK_MINSL	0
+	"min_sl",
+#define	SAK_MAXSL	1
+	"max_sl",
+#define	SAK_DOI		2
+	"doi",
+#define	SAK_CIPSO	3
+	"cipso",
+#define	SAK_INVAL	4
+	NULL
+};
+
+const char *
+rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
+{
+	size_t slen;
+	uint32_t mask, i;
+
+	slen = 0;
+	*line = '\0';
+	mask = rtsa->rtsa_mask;
+
+	for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
+		if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
+			continue;
+		if (!(i & mask))
+			continue;
+		if (slen != 0)
+			line[slen++] = ',';
+		switch (i & mask) {
+		case RTSA_MINSL:
+			slen += snprintf(line + slen, len - slen, "min_sl=%s",
+			    sl_to_str(&rtsa->rtsa_slrange.lower_bound));
+			break;
+		case RTSA_MAXSL:
+			slen += snprintf(line + slen, len - slen, "max_sl=%s",
+			    sl_to_str(&rtsa->rtsa_slrange.upper_bound));
+			break;
+		case RTSA_DOI:
+			slen += snprintf(line + slen, len - slen, "doi=%d",
+			    rtsa->rtsa_doi);
+			break;
+		case RTSA_CIPSO:
+			slen += snprintf(line + slen, len - slen, "cipso");
+			break;
+		}
+	}
+
+	return (line);
+}
+
+boolean_t
+rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
+{
+	const char *valptr, *nxtopt;
+	uint32_t mask = 0, doi;
+	int key;
+	bslabel_t min_sl, max_sl;
+	char attrbuf[MAX_ATTR_LEN];
+	const char **keyword;
+	int err;
+	char *errstr, *cp;
+
+	if (errp == NULL)
+		errp = &err;
+	if (errstrp == NULL)
+		errstrp = &errstr;
+
+	*errstrp = (char *)options;
+
+	while (*options != '\0') {
+		valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
+
+		if (attrbuf[0] == '\0') {
+			*errstrp = (char *)options;
+			*errp = LTSNET_ILL_ENTRY;
+			return (B_FALSE);
+		}
+		for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
+			if (strcmp(*keyword, attrbuf) == 0)
+				break;
+		if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
+			*errstrp = (char *)options;
+			*errp = LTSNET_ILL_KEY;
+			return (B_FALSE);
+		}
+		if ((key == SAK_CIPSO && *valptr == '=') ||
+		    (key != SAK_CIPSO && *valptr != '=')) {
+			*errstrp = (char *)valptr;
+			*errp = LTSNET_ILL_VALDELIM;
+			return (B_FALSE);
+		}
+
+		nxtopt = valptr;
+		if (*valptr == '=') {
+			valptr++;
+			nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
+			    valptr, ",=");
+			if (*nxtopt == '=') {
+				*errstrp = (char *)nxtopt;
+				*errp = LTSNET_ILL_KEYDELIM;
+				return (B_FALSE);
+			}
+		}
+		if (*nxtopt == ',')
+			nxtopt++;
+
+		switch (key) {
+		case SAK_MINSL:
+			if (mask & RTSA_MINSL) {
+				*errstrp = (char *)options;
+				*errp = LTSNET_DUP_KEY;
+				return (B_FALSE);
+			}
+			if (stobsl(attrbuf, &min_sl, NO_CORRECTION,
+			    &err) != 1) {
+				*errstrp = (char *)valptr;
+				*errp = LTSNET_ILL_LOWERBOUND;
+				return (B_FALSE);
+			}
+			mask |= RTSA_MINSL;
+			break;
+
+		case SAK_MAXSL:
+			if (mask & RTSA_MAXSL) {
+				*errstrp = (char *)options;
+				*errp = LTSNET_DUP_KEY;
+				return (B_FALSE);
+			}
+			if (stobsl(attrbuf, &max_sl, NO_CORRECTION,
+			    &err) != 1) {
+				*errstrp = (char *)valptr;
+				*errp = LTSNET_ILL_UPPERBOUND;
+				return (B_FALSE);
+			}
+			mask |= RTSA_MAXSL;
+			break;
+
+		case SAK_DOI:
+			if (mask & RTSA_DOI) {
+				*errstrp = (char *)options;
+				*errp = LTSNET_DUP_KEY;
+				return (B_FALSE);
+			}
+			errno = 0;
+			doi = strtoul(attrbuf, &cp, 0);
+			if (doi == 0 || errno != 0 || *cp != '\0') {
+				*errstrp = (char *)valptr;
+				*errp = LTSNET_ILL_DOI;
+				return (B_FALSE);
+			}
+			mask |= RTSA_DOI;
+			break;
+
+		case SAK_CIPSO:
+			if (mask & RTSA_CIPSO) {
+				*errstrp = (char *)options;
+				*errp = LTSNET_DUP_KEY;
+				return (B_FALSE);
+			}
+			mask |= RTSA_CIPSO;
+			break;
+		}
+
+		options = nxtopt;
+	}
+
+	/* Defaults to CIPSO if not specified */
+	mask |= RTSA_CIPSO;
+
+	/* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
+	if (!(mask & RTSA_DOI)) {
+		*errp = LTSNET_NO_DOI;
+		return (B_FALSE);
+	}
+
+	/* SL range must be specified */
+	if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
+		*errp = LTSNET_NO_RANGE;
+		return (B_FALSE);
+	}
+	if (!(mask & RTSA_MINSL)) {
+		*errp = LTSNET_NO_LOWERBOUND;
+		return (B_FALSE);
+	}
+	if (!(mask & RTSA_MAXSL)) {
+		*errp = LTSNET_NO_UPPERBOUND;
+		return (B_FALSE);
+	}
+
+	/* SL range must have upper bound dominating lower bound */
+	if (!bldominates(&max_sl, &min_sl)) {
+		*errp = LTSNET_ILL_RANGE;
+		return (B_FALSE);
+	}
+
+	if (mask & RTSA_MINSL)
+		sp->rtsa_slrange.lower_bound = min_sl;
+	if (mask & RTSA_MAXSL)
+		sp->rtsa_slrange.upper_bound = max_sl;
+	if (mask & RTSA_DOI)
+		sp->rtsa_doi = doi;
+	sp->rtsa_mask = mask;
+
+	return (B_TRUE);
+}
+
+/* Keep in sync with libtsnet.h */
+static const char *tsol_errlist[] = {
+	"No error",
+	"System error",
+	"Empty string or end of list",
+	"Entry is malformed",
+	"Missing name",
+	"Missing attributes",
+	"Illegal name",
+	"Illegal keyword delimiter",
+	"Unknown keyword",
+	"Duplicate keyword",
+	"Illegal value delimiter",
+	"Missing host type",
+	"Illegal host type",
+	"Missing label",
+	"Illegal label",
+	"Missing label range",
+	"Illegal label range",
+	"No lower bound in range",
+	"Illegal lower bound in range",
+	"No upper bound in range",
+	"Illegal upper bound in range",
+	"Missing DOI",
+	"Illegal DOI",
+	"Too many entries in set",
+	"Missing address/network",
+	"Illegal address/network",
+	"Illegal flag",
+	"Illegal MLP specification",
+	"Unacceptable keyword for type"
+};
+static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
+
+const char *
+tsol_strerror(int libtserr, int errnoval)
+{
+	if (libtserr == LTSNET_SYSERR)
+		return (strerror(errnoval));
+	if (libtserr >= 0 && libtserr < tsol_nerr)
+		return (gettext(tsol_errlist[libtserr]));
+	return (gettext("Unknown error"));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/synonyms.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.   All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From "synonyms.h	7.2	99/06/21 SMI; TSOL 2.x"
+ */
+
+#ifndef	_SYNONYMS_H
+#define	_SYNONYMS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#if defined(__STDC__)
+
+/* external data */
+
+/* functions */
+#define	tnrh			_tnrh
+#define	tnrhtp			_tnrhtp
+#define	tnmlp			_tnmlp
+
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYNONYMS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tnmlp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,49 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include	"synonyms.h"
+#include	<sys/types.h>
+#include	<sys/syscall.h>
+#include 	<libtsnet.h>
+#include	<sys/tsol/tsyscall.h>
+
+/*
+ * tnmlp(2TSOL) - manipulate kernel trusted network multilevel port
+ *                entries
+ *
+ * This is the library interface to the system call.
+ */
+
+#ifdef __STDC__
+#pragma weak tnmlp = _tnmlp
+#endif
+
+int
+tnmlp(int cmd, tsol_mlpent_t *buf)
+{
+	return (syscall(SYS_labelsys, TSOL_TNMLP, cmd, buf));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tnrh.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include	"synonyms.h"
+#include	<sys/types.h>
+#include	<sys/syscall.h>
+#include 	<libtsnet.h>
+#include	<sys/tsol/tsyscall.h>
+
+/*
+ * tnrh(2TSOL) - manipulate kernel trusted network remote hosts cache
+ *
+ * This is the library interface to the system call.
+ */
+
+#ifdef __STDC__
+#pragma weak tnrh = _tnrh
+#endif
+
+int
+tnrh(int cmd, tsol_rhent_t *buf)
+{
+	return (syscall(SYS_labelsys, TSOL_TNRH, cmd, buf));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tnrhtp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,49 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include	"synonyms.h"
+#include	<sys/types.h>
+#include	<sys/syscall.h>
+#include 	<libtsnet.h>
+#include	<sys/tsol/tsyscall.h>
+
+/*
+ * tnrhtp(2TSOL) - manipulate kernel trusted network remote host
+ *                 templates cache
+ *
+ * This is the library interface to the system call.
+ */
+
+#ifdef __STDC__
+#pragma weak tnrhtp = _tnrhtp
+#endif
+
+int
+tnrhtp(int cmd, tsol_tpent_t *buf)
+{
+	return (syscall(SYS_labelsys, TSOL_TNRHTP, cmd, buf));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_getrhent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,257 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From "tsol_getrhent.c	7.6	00/09/22 SMI; TSOL 2.x"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <nss_dbdefs.h>
+#include <libtsnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <secdb.h>
+#include <nss.h>
+#include <libtsnet.h>
+#include <libintl.h>
+
+extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);	/* from lib.c */
+
+static int tsol_rh_stayopen;	/* Unsynchronized, but it affects only	*/
+				/*   efficiency, not correctness	*/
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static void
+_nss_initf_tsol_rh(nss_db_params_t *p)
+{
+	p->name	= NSS_DBNAM_TSOL_RH;
+	p->default_config = NSS_DEFCONF_TSOL_RH;
+}
+
+tsol_rhent_t *
+tsol_getrhbyaddr(const void *addrp, size_t len, int af)
+{
+	int		err = 0;
+	char		*errstr = NULL;
+	char		buf[NSS_BUFLEN_TSOL_RH];
+	tsol_rhstr_t	result;
+	tsol_rhstr_t	*rhstrp = NULL;
+	nss_XbyY_args_t arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_rhstr);
+
+	arg.key.hostaddr.addr = (const char *)addrp;
+	arg.key.hostaddr.len = len;
+	arg.key.hostaddr.type = af;
+	arg.stayopen = tsol_rh_stayopen;
+	arg.h_errno = TSOL_NOT_FOUND;
+	arg.status = nss_search(&db_root, _nss_initf_tsol_rh,
+	    NSS_DBOP_TSOL_RH_BYADDR, &arg);
+	rhstrp = (tsol_rhstr_t *)NSS_XbyY_FINI(&arg);
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "tsol_getrhbyaddr %s: %s\n",
+	    (char *)addrp, rhstrp ? rhstrp->template : "NULL");
+#endif	/* DEBUG */
+
+	if (rhstrp == NULL)
+		return (NULL);
+
+	return (rhstr_to_ent(rhstrp, &err, &errstr));
+}
+
+void
+tsol_setrhent(int stay)
+{
+	tsol_rh_stayopen |= stay;
+	nss_setent(&db_root, _nss_initf_tsol_rh, &context);
+}
+
+void
+tsol_endrhent(void)
+{
+	tsol_rh_stayopen = 0;
+	nss_endent(&db_root, _nss_initf_tsol_rh, &context);
+	nss_delete(&db_root);
+}
+
+tsol_rhent_t *
+tsol_getrhent(void)
+{
+	int			err = 0;
+	char			*errstr = NULL;
+	char			buf[NSS_BUFLEN_TSOL_RH];
+	tsol_rhstr_t		result;
+	tsol_rhstr_t		*rhstrp = NULL;
+	nss_XbyY_args_t		arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_rhstr);
+	/* No key, no stayopen */
+	arg.status = nss_getent(&db_root, _nss_initf_tsol_rh, &context, &arg);
+	rhstrp = (tsol_rhstr_t *)NSS_XbyY_FINI(&arg);
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "tsol_getrhent: %s\n",
+	    rhstrp ? rhstrp->template : "NULL");
+#endif	/* DEBUG */
+
+	if (rhstrp == NULL)
+		return (NULL);
+
+	return (rhstr_to_ent(rhstrp, &err, &errstr));
+}
+
+tsol_rhent_t *
+tsol_fgetrhent(FILE *f)
+{
+	int		err = 0;
+	char		*errstr = NULL;
+	char		buf[NSS_BUFLEN_TSOL_RH];
+	tsol_rhstr_t	result;
+	tsol_rhstr_t	*rhstrp = NULL;
+	tsol_rhent_t	*rhentp = NULL;
+	nss_XbyY_args_t	arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_rhstr);
+	_nss_XbyY_fgets(f, &arg);
+	rhstrp = (tsol_rhstr_t *)NSS_XbyY_FINI(&arg);
+	if (rhstrp == NULL)
+		return (NULL);
+	rhentp = rhstr_to_ent(rhstrp, &err, &errstr);
+	while (rhentp == NULL) {
+		/*
+		 * Loop until we find a non-blank, non-comment line, or
+		 * until EOF. No need to log blank lines, comments.
+		 */
+		if (err != LTSNET_EMPTY)
+			(void) fprintf(stderr, "%s: %.32s%s: %s\n",
+			    gettext("Error parsing tnrhdb file"), errstr,
+			    (strlen(errstr) > 32)? "...": "",
+			    (char *)tsol_strerror(err, errno));
+		_nss_XbyY_fgets(f, &arg);
+		rhstrp = (tsol_rhstr_t *)NSS_XbyY_FINI(&arg);
+		if (rhstrp == NULL)	/* EOF */
+			return (NULL);
+		rhentp = rhstr_to_ent(rhstrp, &err, &errstr);
+	}
+	return (rhentp);
+}
+
+/*
+ * This is the callback routine for nss.
+ */
+int
+str_to_rhstr(const char *instr, int lenstr, void *entp, char *buffer,
+    int buflen)
+{
+	int		len;
+	char		*str = NULL;
+	char		*last = NULL;
+	char		*sep = KV_TOKEN_DELIMIT;
+	tsol_rhstr_t	*rhstrp = (tsol_rhstr_t *)entp;
+
+	if ((instr >= buffer && (buffer + buflen) > instr) ||
+	    (buffer >= instr && (instr + lenstr) > buffer))
+		return (NSS_STR_PARSE_PARSE);
+	if (lenstr >= buflen)
+		return (NSS_STR_PARSE_ERANGE);
+	(void) strncpy(buffer, instr, buflen);
+	str = _strtok_escape(buffer, sep, &last);
+	rhstrp->address = _do_unescape(str);
+	/*
+	 * _do_unesape uses isspace() which removes "\n".
+	 * we keep "\n" as we use it in checking for
+	 * blank lines.
+	 */
+	if (strcmp(instr, "\n") == 0)
+		rhstrp->address = "\n";
+	rhstrp->template = _strtok_escape(NULL, sep, &last);
+	if (rhstrp->template != NULL) {
+		len = strlen(rhstrp->template);
+		if (rhstrp->template[len - 1] == '\n')
+			rhstrp->template[len - 1] = '\0';
+	}
+	if (rhstrp->address == NULL)
+		rhstrp->family = 0;
+	else if (strchr(rhstrp->address, ':') == NULL)
+		rhstrp->family = AF_INET;
+	else
+		rhstrp->family = AF_INET6;
+
+#ifdef	DEBUG
+	(void) fprintf(stdout,
+	    "str_to_rhstr:str - %s\taddress - %s\n\ttemplate - %s\n",
+	    instr, rhstrp->address ? rhstrp->address : "NULL",
+	    rhstrp->template ? rhstrp->template : "NULL");
+#endif	/* DEBUG */
+
+	return (NSS_STR_PARSE_SUCCESS);
+}
+
+tsol_host_type_t
+tsol_getrhtype(char *rhost) {
+	int herr;
+	struct hostent *hp;
+	in6_addr_t in6;
+	char abuf[INET6_ADDRSTRLEN];
+	tsol_rhent_t rhent;
+	tsol_tpent_t tp;
+
+	if ((hp = getipnodebyname(rhost, AF_INET6,
+	    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &herr)) == NULL) {
+		return (UNLABELED);
+	}
+
+	(void) memset(&rhent, 0, sizeof (rhent));
+	(void) memcpy(&in6, hp->h_addr, hp->h_length);
+
+	if (IN6_IS_ADDR_V4MAPPED(&in6)) {
+		rhent.rh_address.ta_family = AF_INET;
+		IN6_V4MAPPED_TO_INADDR(&in6, &rhent.rh_address.ta_addr_v4);
+		(void) inet_ntop(AF_INET, &rhent.rh_address.ta_addr_v4, abuf,
+		    sizeof (abuf));
+	} else {
+		rhent.rh_address.ta_family = AF_INET6;
+		rhent.rh_address.ta_addr_v6 = in6;
+		(void) inet_ntop(AF_INET6, &in6, abuf, sizeof (abuf));
+	}
+
+	if (tnrh(TNDB_GET, &rhent) != 0)
+		return (UNLABELED);
+
+	if (rhent.rh_template[0] == '\0')
+		return (UNLABELED);
+
+	(void) strlcpy(tp.name, rhent.rh_template, sizeof (tp.name));
+
+	if (tnrhtp(TNDB_GET, &tp) != 0)
+		return (UNLABELED);
+
+	return (tp.host_type);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_gettpent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From "tsol_gettpent.c	7.13	00/10/13 SMI; TSOL 2.x"
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <nss_dbdefs.h>
+#include <libtsnet.h>
+#include <secdb.h>
+#include <nss.h>
+#include <libintl.h>
+
+extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);	/* from lib.c */
+
+static int tsol_tp_stayopen;	/* Unsynchronized, but it affects only	*/
+				/*   efficiency, not correctness	*/
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+
+static void
+_nss_initf_tsol_tp(nss_db_params_t *p)
+{
+	p->name	= NSS_DBNAM_TSOL_TP;
+	p->default_config = NSS_DEFCONF_TSOL_TP;
+}
+
+tsol_tpent_t *
+tsol_gettpbyname(const char *name)
+{
+	int		err = 0;
+	char		*errstr = NULL;
+	char		buf[NSS_BUFLEN_TSOL_TP];
+	tsol_tpstr_t	result;
+	tsol_tpstr_t	*tpstrp = NULL;
+	nss_XbyY_args_t arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_tpstr);
+
+	arg.key.name	= name;
+	arg.stayopen	= tsol_tp_stayopen;
+	arg.h_errno	= TSOL_NOT_FOUND;
+	arg.status = nss_search(&db_root, _nss_initf_tsol_tp,
+	    NSS_DBOP_TSOL_TP_BYNAME, &arg);
+	tpstrp = (tsol_tpstr_t *)NSS_XbyY_FINI(&arg);
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "tsol_gettpbyname %s: %s\n",
+	    name, tpstrp ? tpstrp->template : "NULL");
+#endif	/* DEBUG */
+
+	if (tpstrp == NULL)
+		return (NULL);
+
+	return (tpstr_to_ent(tpstrp, &err, &errstr));
+}
+
+void
+tsol_settpent(int stay)
+{
+	tsol_tp_stayopen |= stay;
+	nss_setent(&db_root, _nss_initf_tsol_tp, &context);
+}
+
+void
+tsol_endtpent(void)
+{
+	tsol_tp_stayopen = 0;
+	nss_endent(&db_root, _nss_initf_tsol_tp, &context);
+	nss_delete(&db_root);
+}
+
+tsol_tpent_t *
+tsol_gettpent(void)
+{
+	int		err = 0;
+	char		*errstr = NULL;
+	char		buf[NSS_BUFLEN_TSOL_TP];
+	tsol_tpstr_t	result;
+	tsol_tpstr_t	*tpstrp = NULL;
+	nss_XbyY_args_t arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_tpstr);
+	/* No key, no stayopen */
+	arg.status = nss_getent(&db_root, _nss_initf_tsol_tp, &context, &arg);
+	tpstrp = (tsol_tpstr_t *)NSS_XbyY_FINI(&arg);
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "tsol_gettpent: %s\n",
+	    tpstrp ? tpstrp->template : "NULL");
+#endif	/* DEBUG */
+
+	if (tpstrp == NULL)
+		return (NULL);
+
+	return (tpstr_to_ent(tpstrp, &err, &errstr));
+}
+
+tsol_tpent_t *
+tsol_fgettpent(FILE *f)
+{
+	int		err = 0;
+	char		*errstr = NULL;
+	char		buf[NSS_BUFLEN_TSOL_TP];
+	tsol_tpstr_t	result;
+	tsol_tpstr_t	*tpstrp = NULL;
+	tsol_tpent_t	*tpentp = NULL;
+	nss_XbyY_args_t	arg;
+
+	NSS_XbyY_INIT(&arg, &result, buf, sizeof (buf), str_to_tpstr);
+	_nss_XbyY_fgets(f, &arg);
+	tpstrp = (tsol_tpstr_t *)NSS_XbyY_FINI(&arg);
+	if (tpstrp == NULL)
+		return (NULL);
+	tpentp = tpstr_to_ent(tpstrp, &err, &errstr);
+	while (tpentp == NULL) {
+		/*
+		 * Loop until we find a non-blank, non-comment line, or
+		 * until EOF. No need to log blank lines, comments.
+		 */
+		if (err != LTSNET_EMPTY)
+			(void) fprintf(stderr, "%s: %.32s%s: %s\n",
+			    gettext("Error parsing tnrhtp file"), errstr,
+			    (strlen(errstr) > 32)? "...": "",
+			    (char *)tsol_strerror(err, errno));
+		_nss_XbyY_fgets(f, &arg);
+		tpstrp = (tsol_tpstr_t *)NSS_XbyY_FINI(&arg);
+		if (tpstrp == NULL)	/* EOF */
+			return (NULL);
+		tpentp = tpstr_to_ent(tpstrp, &err, &errstr);
+	}
+	return (tpentp);
+}
+
+/*
+ * This is the callback routine for nss.  It just wraps the tsol_sgettpent
+ * parser.
+ */
+int
+str_to_tpstr(const char *instr, int lenstr, void *entp, char *buffer,
+    int buflen)
+{
+	int		len;
+	char		*last = NULL;
+	char		*sep = KV_TOKEN_DELIMIT;
+	tsol_tpstr_t	*tpstrp = (tsol_tpstr_t *)entp;
+
+	if ((instr >= buffer && (buffer + buflen) > instr) ||
+	    (buffer >= instr && (instr + lenstr) > buffer))
+		return (NSS_STR_PARSE_PARSE);
+	if (lenstr >= buflen)
+		return (NSS_STR_PARSE_ERANGE);
+	(void) strncpy(buffer, instr, buflen);
+	tpstrp->template = _strtok_escape(buffer, sep, &last);
+	tpstrp->attrs = _strtok_escape(NULL, sep, &last);
+	if (tpstrp->attrs != NULL) {
+		len = strlen(tpstrp->attrs);
+		if (tpstrp->attrs[len - 1] == '\n')
+			tpstrp->attrs[len - 1] = '\0';
+	}
+
+#ifdef	DEBUG
+	(void) fprintf(stdout,
+	    "str_to_tpstr:\nstr - %s\n\ttemplate - %s\n\tattrs - %s\n",
+	    instr, tpstrp->template ? tpstrp->template : "NULL",
+	    tpstrp->attrs ? tpstrp->attrs : "NULL");
+#endif	/* DEBUG */
+
+	return (NSS_STR_PARSE_SUCCESS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_getzcent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <ctype.h>
+#include <nss_dbdefs.h>
+#include <libtsnet.h>
+
+static int tsol_zc_stayopen;	/* Unsynchronized, but it affects only	*/
+				/*   efficiency, not correctness	*/
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+struct zc_args {
+	tsol_zcent_t *zc;
+	int err;
+	char *errstr;
+	int errno_val;
+};
+
+static int str2tsol_zcent(const char *, int, void *, char *, int);
+
+static void
+_nss_initf_tsol_zc(nss_db_params_t *p)
+{
+	p->name	= NSS_DBNAM_TSOL_ZC;
+	p->default_config = NSS_DEFCONF_TSOL_ZC;
+}
+
+/*
+ * This is just a placeholder.  The system doesn't currently lookup tnzonecfg
+ * entries via name services.
+ */
+/* ARGSUSED */
+static void
+switch_callback(void *res, const char *zonename, const char *label,
+    const char *flags, const char *privmlp, const char *globalmlp)
+{
+}
+
+tsol_zcent_t *
+tsol_getzcbyname(const char *name)
+{
+	nss_XbyY_args_t arg;
+	struct zc_args	zcargs;
+
+	zcargs.zc = NULL;
+	NSS_XbyY_INIT(&arg, &zcargs, (char *)switch_callback, 1,
+	    str2tsol_zcent);
+	arg.key.name	= name;
+	arg.stayopen	= tsol_zc_stayopen;
+	arg.h_errno	= TSOL_NOT_FOUND;
+	arg.status = nss_search(&db_root, _nss_initf_tsol_zc,
+	    NSS_DBOP_TSOL_ZC_BYNAME, &arg);
+	(void) NSS_XbyY_FINI(&arg);
+	if (arg.status != 0) {
+		tsol_freezcent(zcargs.zc);
+		zcargs.zc = NULL;
+	}
+	return (zcargs.zc);
+}
+
+void
+tsol_setzcent(int stay)
+{
+	tsol_zc_stayopen |= stay;
+	nss_setent(&db_root, _nss_initf_tsol_zc, &context);
+}
+
+void
+tsol_endzcent(void)
+{
+	tsol_zc_stayopen = 0;
+	nss_endent(&db_root, _nss_initf_tsol_zc, &context);
+	nss_delete(&db_root);
+}
+
+struct tsol_zcent *
+tsol_getzcent(void)
+{
+	nss_XbyY_args_t arg;
+	struct zc_args zcargs;
+
+	zcargs.zc = NULL;
+	zcargs.errno_val = errno;
+	NSS_XbyY_INIT(&arg, &zcargs, (char *)switch_callback, 1,
+	    str2tsol_zcent);
+	/* No key, no stayopen */
+	arg.status = nss_getent(&db_root, _nss_initf_tsol_zc, &context, &arg);
+	(void) NSS_XbyY_FINI(&arg);
+	if (arg.status != 0) {
+		tsol_freezcent(zcargs.zc);
+		zcargs.zc = NULL;
+	}
+	if (zcargs.zc == NULL && zcargs.err == LTSNET_SYSERR)
+		errno = zcargs.errno_val;
+	return (zcargs.zc);
+}
+
+/*
+ * This is the callback routine for nss.  It just wraps the tsol_sgetzcent
+ * parser.
+ */
+/* ARGSUSED */
+static int
+str2tsol_zcent(const char *instr, int lenstr, void *entp, char *buffer,
+    int buflen)
+{
+	struct zc_args *zcargs = entp;
+
+	if (zcargs->zc != NULL)
+		tsol_freezcent(zcargs->zc);
+	zcargs->zc = tsol_sgetzcent(instr, &zcargs->err, &zcargs->errstr);
+	zcargs->errno_val = errno;
+
+	return (zcargs->zc == NULL ? NSS_STR_PARSE_PARSE :
+	    NSS_STR_PARSE_SUCCESS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_sgetrhent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From	"tsol_tndb_parser.c	7.24	01/09/05 SMI; TSOL 2.x"
+ *
+ * These functions parse entries in the "thrhdb" (remote host database) file.
+ * Each entry in the file has two fields, separated by a colon.  The first
+ * field is the IP host or network address.  The second is the name of the
+ * template to use (from tnrhtp).
+ *
+ * In order to help preserve sanity, we do not allow more than one unescaped
+ * colon in a line.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <libtsnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <inet/ip.h>
+#include <arpa/inet.h>
+#include <nss.h>
+#include <errno.h>
+
+/*
+ * This routine deals with old pre-CIDR subnet address specifications.  In the
+ * bad old days, a subnet was represented as:
+ *
+ *	Expression	Implied Prefix
+ *	10.1.1.0	/24
+ *	10.1.0.0	/16
+ *	10.0.0.0	/8
+ *	0.0.0.0		/0
+ */
+static int
+get_classful_prefix(in_addr_t addr)
+{
+	int bits;
+
+	if (addr == 0)
+		return (0);
+	addr = ntohl(addr);
+	for (bits = IP_ABITS; bits > 0 && (addr & 0xFF) == 0; bits -= 8)
+		addr >>= 8;
+
+	return (bits);
+}
+
+/*
+ * This routine deals with old pre-CIDR network address specifications.  In the
+ * bad old days, a network was represented as:
+ *
+ *	Expression	Implied Prefix
+ *	10.1.1		/24
+ *	10.1		/16
+ *	10		/8
+ *
+ * This routine must compute the mask and left-align the address.
+ */
+static int
+get_network_prefix(in_addr_t *addrp)
+{
+	int bits;
+	in_addr_t addr;
+
+	addr = ntohl(*addrp);
+	for (bits = IP_ABITS; bits > 0 && addr < 0x01000000; bits -= 8)
+		addr <<= 8;
+	*addrp = htonl(addr);
+
+	return (bits);
+}
+
+static boolean_t
+parse_address(tsol_rhent_t *rh, const char *addrbuf)
+{
+	int upper_lim;
+	int len;
+	const uchar_t *aptr;
+
+	if (strchr(addrbuf, ':') == NULL) {
+		/* IPv4 address */
+		rh->rh_address.ta_family = AF_INET;
+		if (inet_pton(AF_INET, addrbuf,
+		    &rh->rh_address.ta_addr_v4) > 0) {
+			if (rh->rh_prefix == -1)
+				rh->rh_prefix = get_classful_prefix(rh->
+				    rh_address.ta_addr_v4.s_addr);
+		} else if ((rh->rh_address.ta_addr_v4.s_addr =
+		    inet_network(addrbuf)) != (in_addr_t)-1) {
+			len = get_network_prefix(&rh->rh_address.ta_addr_v4.
+			    s_addr);
+			if (rh->rh_prefix == -1)
+				rh->rh_prefix = len;
+		} else {
+			return (B_FALSE);
+		}
+		upper_lim = IP_ABITS;
+		aptr = (const uchar_t *)&rh->rh_address.ta_addr_v4;
+	} else {
+		/* IPv6 address */
+		rh->rh_address.ta_family = AF_INET6;
+		if (inet_pton(AF_INET6, addrbuf,
+		    &rh->rh_address.ta_addr_v6) <= 0)
+			return (B_FALSE);
+		if (rh->rh_prefix == -1)
+			rh->rh_prefix = IPV6_ABITS;
+		upper_lim = IPV6_ABITS;
+		aptr = (const uchar_t *)&rh->rh_address.ta_addr_v6;
+	}
+
+	if (rh->rh_prefix < 0 || rh->rh_prefix > upper_lim)
+		return (B_FALSE);
+
+	/*
+	 * Verify that there are no bits set in the "host" portion of the
+	 * IP address.
+	 */
+	len = rh->rh_prefix;
+	aptr += len / 8;
+	if ((len & 7) != 0) {
+		if ((*aptr++ & (0xff >> (len & 7))) != 0)
+			return (B_FALSE);
+		len = (len + 7) & ~7;
+	}
+	while (len < upper_lim) {
+		if (*aptr++ != 0)
+			return (B_FALSE);
+		len += 8;
+	}
+
+	return (B_TRUE);
+}
+
+tsol_rhent_t *
+rhstr_to_ent(tsol_rhstr_t *rhstrp, int *errp, char **errstrp)
+{
+	int		len;
+	int		err = 0;
+	char		*cp, *cp2, *errstr;
+	char		*address = rhstrp->address;
+	char		*template = rhstrp->template;
+	char		addrbuf[1024];
+	tsol_rhent_t	*rhentp = NULL;
+
+	/*
+	 * The user can specify NULL pointers for these.  Make sure that we
+	 * don't have to deal with checking for NULL everywhere by just
+	 * pointing to our own variables if the user gives NULL.
+	 */
+	if (errp == NULL)
+		errp = &err;
+	if (errstrp == NULL)
+		errstrp = &errstr;
+	/* The default, unless we find a more specific error locus. */
+	*errstrp = address;
+
+	if (address == NULL || *address == '#' || *address == '\n') {
+		*errp = LTSNET_EMPTY;
+		if (template && *template != '\0' && *template != '#' &&
+		    *template != '\n')
+			*errstrp = template;
+		else if (address == NULL)
+			*errstrp = "   ";
+		goto err_ret;
+	}
+	if (*address == '\0') {
+		*errp = LTSNET_NO_ADDR;
+		if (template && *template != '\0' && *template != '#' &&
+		    *template != '\n')
+			*errstrp = template;
+		goto err_ret;
+	}
+	if (template == NULL || *template == '#' || *template == '\n' ||
+	    *template == '\0') {
+		*errp = LTSNET_NO_HOSTTYPE;
+		goto err_ret;
+	}
+	if ((rhentp = calloc(1, sizeof (*rhentp))) == NULL) {
+		*errp = LTSNET_SYSERR;
+		return (NULL);
+	}
+	if ((cp = strrchr(address, '/')) != NULL) {
+		len = cp - address;
+		if (len >= sizeof (addrbuf)) {
+			*errp = LTSNET_ILL_ADDR;
+			goto err_ret;
+		}
+		(void) memset(addrbuf, '\0', sizeof (addrbuf));
+		(void) memcpy(addrbuf, address, len);
+		cp++;
+		errno = 0;
+		rhentp->rh_prefix = strtol(cp, &cp2, 0);
+		if (errno != 0) {
+			*errp = LTSNET_SYSERR;
+			*errstrp = cp2;
+			goto err_ret;
+		}
+		if ((isdigit(*cp) == 0)) {
+			*errp = LTSNET_ILL_ADDR;
+			*errstrp = address;
+			goto err_ret;
+		}
+	} else {
+		rhentp->rh_prefix = -1;
+		(void) strlcpy(addrbuf, address, sizeof (addrbuf));
+	}
+	if (strlcpy(rhentp->rh_template, template,
+	    sizeof (rhentp->rh_template)) >= sizeof (rhentp->rh_template)) {
+		*errstrp = template;
+		*errp = LTSNET_ILL_NAME;
+		goto err_ret;
+	}
+	if (!parse_address(rhentp, addrbuf)) {
+		*errp = LTSNET_ILL_ADDR;
+		*errstrp = address;
+		goto err_ret;
+	}
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "rhstr_to_ent: %s:%s\n",
+	    address, rhentp->rh_template);
+#endif	/* DEBUG */
+
+	return (rhentp);
+
+err_ret:
+	err = errno;
+	tsol_freerhent(rhentp);
+	errno = err;
+#ifdef	DEBUG
+	(void) fprintf(stderr, "\nrhstr_to_ent: %s: %s\n",
+	    *errstrp, (char *)tsol_strerror(*errp, errno));
+#endif	/* DEBUG */
+
+	return (NULL);
+}
+
+void
+tsol_freerhent(tsol_rhent_t *rh)
+{
+	if (rh != NULL)
+		free(rh);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_sgettpent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,301 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From	"tsol_tndb_parser.c	7.24	01/09/05 SMI; TSOL 2.x"
+ *
+ * These functions parse entries in the "tnrhtp" (remote host template) file.
+ * Each entry in this file has two fields, separated by a colon.  The first
+ * field is the template name.  The second is a list of "key=value" attributes,
+ * separated by semicolons.
+ *
+ * In order to help preserve sanity, we do not allow more than one unescaped
+ * colon in a line, nor any unescaped '=' or ';' characters in the template
+ * name.  Such things are indicative of typing errors, not intentional
+ * configuration.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <libtsnet.h>
+#include <tsol/label.h>
+#include <sys/types.h>
+#include <nss.h>
+#include <secdb.h>
+#include <errno.h>
+
+static int
+get_tn_doi(tsol_tpent_t *tpentp, kva_t *kv)
+{
+	char	*cp;
+	char	*val = NULL;
+
+	val = kva_match(kv, TP_DOI);
+	if (val == NULL)
+		return (LTSNET_NO_DOI);
+
+	errno = 0;
+	tpentp->tp_doi = strtol(val, &cp, 0);
+	if (errno != 0)
+		return (LTSNET_SYSERR);
+	if (*cp != '\0')
+		return (LTSNET_ILL_DOI);
+
+	return (0);
+}
+
+static int
+get_tn_sl_range(brange_t *range, char *min, char *max)
+{
+	int	err = 0;
+
+	if (min == NULL && max == NULL)
+		return (LTSNET_NO_RANGE);
+	if (min == NULL)
+		return (LTSNET_NO_LOWERBOUND);
+	if (max == NULL)
+		return (LTSNET_NO_UPPERBOUND);
+
+	if (stobsl(min, &range->lower_bound, NO_CORRECTION, &err) == 0)
+		return (LTSNET_ILL_LOWERBOUND);
+	if (stobsl(max, &range->upper_bound, NO_CORRECTION, &err) == 0)
+		return (LTSNET_ILL_UPPERBOUND);
+	if (!bldominates(&range->upper_bound, &range->lower_bound))
+		return (LTSNET_ILL_RANGE);
+
+	return (0);
+}
+
+static int
+get_tn_sl_set(blset_t *labelset, char *setstr)
+{
+	int		sc, err;
+	char		*tokp, *finally;
+	bslabel_t	*labels;
+
+	(void) memset(labelset, 0, sizeof (blset_t));
+	labels = (bslabel_t *)labelset;
+	tokp = strtok_r(setstr, TNDB_COMMA, &finally);
+	for (sc = 0; tokp != NULL && sc < NSLS_MAX; sc++) {
+		if (stobsl(tokp, &labels[sc], NO_CORRECTION, &err) == 0)
+			return (LTSNET_ILL_LABEL);
+		tokp = strtok_r(NULL, TNDB_COMMA, &finally);
+	}
+	if (tokp != NULL && sc >= NSLS_MAX)
+		return (LTSNET_SET_TOO_BIG);
+
+	return (0);
+}
+
+static int
+parse_remainder(tsol_tpent_t *tpentp, kva_t *kv)
+{
+	int	err = 0;
+	char	*val = NULL;
+	char	*val2 = NULL;
+
+	val = kva_match(kv, TP_HOSTTYPE);
+
+	if (val == NULL)
+		return (LTSNET_NO_HOSTTYPE);
+	if (strcasecmp(val, TP_UNLABELED) == 0)
+		tpentp->host_type = UNLABELED;
+	else if (strcasecmp(val, TP_CIPSO) == 0)
+		tpentp->host_type = SUN_CIPSO;
+	else
+		return (LTSNET_ILL_HOSTTYPE);
+
+	/*
+	 * parse fields by host type -
+	 * add on to the following if statement for each new host type.
+	 */
+	if (tpentp->host_type == UNLABELED) {
+		tpentp->tp_mask_unl = 0;
+		/*
+		 * doi
+		 */
+		if ((err = get_tn_doi(tpentp, kv)) != 0)
+			return (err);
+		tpentp->tp_mask_unl |= TSOL_MSK_CIPSO_DOI;
+		/*
+		 * default label
+		 */
+		val = kva_match(kv, TP_DEFLABEL);
+		if (val == NULL)
+			return (LTSNET_NO_LABEL);
+		if (stobsl(val, &tpentp->tp_def_label, NO_CORRECTION,
+		    &err) == 0)
+			return (LTSNET_ILL_LABEL);
+		tpentp->tp_mask_unl |= TSOL_MSK_DEF_LABEL;
+		/*
+		 * check label range
+		 */
+		val = kva_match(kv, TP_MINLABEL);
+		val2 = kva_match(kv, TP_MAXLABEL);
+		if (val == NULL && val2 == NULL) {
+			/*
+			 * This is the old format.  Use ADMIN_LOW to SL of the
+			 * default label as the gw_sl_range.
+			 */
+			bsllow(&tpentp->tp_gw_sl_range.lower_bound);
+			tpentp->tp_gw_sl_range.upper_bound =
+			    tpentp->tp_def_label;
+		} else {
+			err = get_tn_sl_range(&tpentp->tp_gw_sl_range, val,
+			    val2);
+			if (err != 0)
+				return (err);
+		}
+		tpentp->tp_mask_unl |= TSOL_MSK_SL_RANGE_TSOL;
+
+		/*
+		 * also label set, if present.  (optional)
+		 */
+		val = kva_match(kv, TP_SET);
+		if (val != NULL) {
+			err = get_tn_sl_set(&tpentp->tp_gw_sl_set, val);
+			if (err != 0)
+				return (err);
+			tpentp->tp_mask_cipso |= TSOL_MSK_SL_RANGE_TSOL;
+		}
+	} else {
+		tpentp->tp_mask_cipso = 0;
+		/*
+		 * doi
+		 */
+		if ((err = get_tn_doi(tpentp, kv)) != 0)
+			return (err);
+		tpentp->tp_mask_cipso |= TSOL_MSK_CIPSO_DOI;
+		/*
+		 * label range
+		 */
+		val = kva_match(kv, TP_MINLABEL);
+		val2 = kva_match(kv, TP_MAXLABEL);
+		err = get_tn_sl_range(&tpentp->tp_sl_range_cipso, val, val2);
+		if (err != 0)
+			return (err);
+		tpentp->tp_mask_cipso |= TSOL_MSK_SL_RANGE_TSOL;
+		/*
+		 * also label set, if present.  (optional)
+		 */
+		val = kva_match(kv, TP_SET);
+		if (val != NULL) {
+			err = get_tn_sl_set(&tpentp->tp_sl_set_cipso, val);
+			if (err != 0)
+				return (err);
+			tpentp->tp_mask_cipso |= TSOL_MSK_SL_RANGE_TSOL;
+		}
+
+		/* CIPSO entries don't support default labels */
+		val = kva_match(kv, TP_DEFLABEL);
+		if (val != NULL)
+			return (LTSNET_BAD_TYPE);
+	}
+
+	return (0);
+}
+
+tsol_tpent_t *
+tpstr_to_ent(tsol_tpstr_t *tpstrp, int *errp, char **errstrp)
+{
+	int		err = 0;
+	char		*errstr;
+	char		*template = tpstrp->template;
+	char		*attrs = tpstrp->attrs;
+	kva_t		*kv;
+	tsol_tpent_t	*tpentp = NULL;
+
+	/*
+	 * The user can specify NULL pointers for these.  Make sure that we
+	 * don't have to deal with checking for NULL everywhere by just
+	 * pointing to our own variables if the user gives NULL.
+	 */
+	if (errp == NULL)
+		errp = &err;
+	if (errstrp == NULL)
+		errstrp = &errstr;
+	/* The default, unless we find a more specific error locus. */
+	*errstrp = template;
+
+	if (template == NULL || *template == '#' || *template == '\n') {
+		*errp = LTSNET_EMPTY;
+		if (attrs && *attrs != '\0' && *attrs != '#' && *attrs != '\n')
+			*errstrp = attrs;
+		else if (template == NULL)
+			*errstrp = "   ";
+		goto err_ret;
+	}
+	if (*template == '\0') {
+		*errp = LTSNET_NO_NAME;
+		if (attrs && *attrs != '\0' && *attrs != '#' && *attrs != '\n')
+		    *errstrp = attrs;
+		goto err_ret;
+	}
+	if (attrs == NULL || *attrs == '\0' || *attrs == '#' ||
+	    *attrs == '\n') {
+		*errp = LTSNET_NO_ATTRS;
+		goto err_ret;
+	}
+	if ((tpentp = calloc(1, sizeof (*tpentp))) == NULL) {
+		*errp = LTSNET_SYSERR;
+		return (NULL);
+	}
+	if (strlcpy(tpentp->name, template, sizeof (tpentp->name)) >=
+	    sizeof (tpentp->name))
+		goto err_ret;
+	kv = _str2kva(attrs, KV_ASSIGN, KV_DELIMITER);
+	*errp = parse_remainder(tpentp, kv);
+	_kva_free(kv);
+	if (*errp == 0) {
+#ifdef	DEBUG
+		(void) fprintf(stdout, "tpstr_to_ent: %s:%s\n", tpentp->name,
+		    attrs);
+#endif	/* DEBUG */
+
+		return (tpentp);
+	}
+
+err_ret:
+	err = errno;
+	tsol_freetpent(tpentp);
+	errno = err;
+#ifdef	DEBUG
+	(void) fprintf(stderr, "\ntpstr_to_ent: %s:%s\n",
+	    *errstrp, (char *)tsol_strerror(*errp, errno));
+#endif	/* DEBUG */
+
+	return (NULL);
+}
+
+void
+tsol_freetpent(tsol_tpent_t *tp)
+{
+	if (tp != NULL)
+		free(tp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/common/tsol_sgetzcent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,285 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * From	"tsol_tndb_parser.c	7.24	01/09/05 SMI; TSOL 2.x"
+ *
+ * These functions parse entries in the "tnzonecfg" (zone configuration) file.
+ * Each entry in this file has five fields, separated by a colon.  These fields
+ * are:
+ *
+ *	zone name : label : flags : zone-specific MLPs : global MLPs
+ *
+ * The fourth and fifth fields contain subfields consisting of MLP entries
+ * separated by semicolons.  The MLP entries are of the form:
+ *
+ *	port[-port]/protocol
+ *
+ * In order to help preserve sanity, we do not allow more than four unescaped
+ * colons in a line, nor any unescaped ';' characters in the non-MLP fields.
+ * Such things are indicative of typing errors, not intentional configuration.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <libtsnet.h>
+#include <tsol/label.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <nss.h>
+#include <errno.h>
+#include <secdb.h>
+
+/*
+ * Parse an MLP specification in port1-port2/proto or port/proto form.
+ */
+static int
+str_to_mlp(char *mlp_str, tsol_mlp_t *zone_mlp)
+{
+	char *fieldp;
+	char *lasts, *cp;
+	int i;
+	ulong_t ulv;
+	struct protoent proto;
+	char gbuf[1024];
+
+	(void) memset(zone_mlp, 0, sizeof (tsol_mlp_t));
+
+	fieldp = strtok_r(mlp_str, KV_DELIMITER, &lasts);
+	if (fieldp == NULL)
+		return (-1);
+
+	errno = 0;
+	for (i = 0; fieldp != NULL && i < NMLP_MAX; i++) {
+		ulv = strtoul(fieldp, &cp, 0);
+		zone_mlp[i].mlp_port = (uint16_t)ulv;
+		zone_mlp[i].mlp_port_upper = 0;
+		if (errno != 0 || ulv > 65535)
+			return (-1);
+		if (*cp == '-') {
+			ulv = strtol(cp + 1, &cp, 0);
+			zone_mlp[i].mlp_port_upper = (uint16_t)ulv;
+			if (errno != 0 || ulv > 65535)
+				return (-1);
+		}
+		if (*cp != '/')
+			return (-1);
+		fieldp = cp + 1;
+		ulv = strtol(fieldp, &cp, 0);
+		if (errno == 0 && ulv <= 255 && *cp == '\0')
+			zone_mlp->mlp_ipp = (uint8_t)ulv;
+		else if (getprotobyname_r(fieldp, &proto, gbuf,
+		    sizeof (gbuf)) != NULL)
+			zone_mlp->mlp_ipp = proto.p_proto;
+		else
+			return (-1);
+		fieldp = strtok_r(NULL, KV_DELIMITER, &lasts);
+	}
+	return (0);
+}
+
+static boolean_t
+parse_mlp_list(tsol_mlp_t **list, char *str, int *errp, char **errstrp)
+{
+	int mmax;
+	tsol_mlp_t *mlp;
+	char *tokp, *finally;
+	int mc;
+
+	mmax = 0;
+	if ((mlp = *list) != NULL) {
+		while (!TSOL_MLP_END(mlp)) {
+			mmax++;
+			mlp++;
+		}
+		mmax++;
+	}
+	mlp = *list;
+	tokp = strtok_r(str, KV_DELIMITER, &finally);
+	for (mc = 0; tokp != NULL; mc++) {
+		if (mc >= mmax) {
+			mmax += 8;
+			mlp = realloc(mlp, mmax * sizeof (*mlp));
+			if (mlp == NULL) {
+				*errp = LTSNET_SYSERR;
+				*errstrp = tokp;
+				return (B_FALSE);
+			}
+			*list = mlp;
+		}
+		if (str_to_mlp(tokp, mlp + mc) == -1) {
+			*errp = LTSNET_ILL_MLP;
+			*errstrp = tokp;
+			return (B_FALSE);
+		}
+		tokp = strtok_r(NULL, KV_DELIMITER, &finally);
+	}
+	if (mc >= mmax) {
+		mlp = realloc(mlp, (mmax + 1) * sizeof (*mlp));
+		if (mlp == NULL) {
+			*errp = LTSNET_SYSERR;
+			*errstrp = finally;
+			return (B_FALSE);
+		}
+		*list = mlp;
+	}
+	(void) memset(mlp + mc, 0, sizeof (*mlp));
+	return (B_TRUE);
+}
+
+tsol_zcent_t *
+tsol_sgetzcent(const char *instr, int *errp, char **errstrp)
+{
+	int err;
+	char *errstr;
+	tsol_zcent_t *zc;
+	const char *nextf;
+	char *cp;
+	char fieldbuf[1024];
+
+	/*
+	 * The user can specify NULL pointers for these.  Make sure that we
+	 * don't have to deal with checking for NULL everywhere by just
+	 * pointing to our own variables if the user gives NULL.
+	 */
+	if (errp == NULL)
+		errp = &err;
+	if (errstrp == NULL)
+		errstrp = &errstr;
+
+	/* The default, unless we find a more specific error locus. */
+	*errstrp = (char *)instr;
+
+	if ((zc = calloc(1, sizeof (*zc))) == NULL) {
+		*errp = LTSNET_SYSERR;
+		return (NULL);
+	}
+
+	/* First, parse off the zone name. */
+	instr = parse_entry(zc->zc_name, sizeof (zc->zc_name), instr, "#;:\n");
+	if (zc->zc_name[0] == '\0') {
+		*errstrp = (char *)instr;
+		if (*instr == '\0' || *instr == '#' || *instr == '\n')
+			*errp = LTSNET_EMPTY;
+		else if (*instr == ':')
+			*errp = LTSNET_NO_NAME;
+		else
+			*errp = LTSNET_ILL_NAME;
+		goto err_ret;
+	}
+	if (*instr != ':') {
+		*errstrp = (char *)instr;
+		if (*instr == '=' || *instr == ';')
+			*errp = LTSNET_ILL_NAME;
+		else
+			*errp = LTSNET_ILL_ENTRY;
+		goto err_ret;
+	}
+	instr++;
+
+	/* Field two: parse off the label. */
+	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#;:\n");
+	if (*nextf != ':') {
+		*errstrp = (char *)nextf;
+		*errp = LTSNET_ILL_ENTRY;
+		goto err_ret;
+	}
+	if (fieldbuf[0] == '\0') {
+		*errstrp = (char *)instr;
+		*errp = LTSNET_NO_LABEL;
+		goto err_ret;
+	}
+	if (stobsl(fieldbuf, &zc->zc_label, NO_CORRECTION, &err) == 0) {
+		*errstrp = (char *)instr;
+		*errp = LTSNET_ILL_LABEL;
+		goto err_ret;
+	}
+	instr = nextf + 1;
+
+	/* Not in the entry, but should be */
+	zc->zc_doi = 1;
+
+	/* Field three: get match flag */
+	errno = 0;
+	zc->zc_match = (uchar_t)strtol(instr, &cp, 0);
+	if (errno != 0 || (*cp != ':' && *cp != '\0')) {
+		*errp = LTSNET_ILL_FLAG;
+		*errstrp = (char *)instr;
+		goto err_ret;
+	}
+	if (*cp != ':') {
+		*errp = LTSNET_ILL_VALDELIM;
+		*errstrp = cp;
+		goto err_ret;
+	}
+	instr = cp + 1;
+
+	/* Field four: get zone-specific MLP list. */
+	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
+	if (*nextf != ':') {
+		*errstrp = (char *)nextf;
+		*errp = LTSNET_ILL_ENTRY;
+		goto err_ret;
+	}
+	if (!parse_mlp_list(&zc->zc_private_mlp, fieldbuf, errp, errstrp)) {
+		*errstrp = (char *)instr + (*errstrp - fieldbuf);
+		goto err_ret;
+	}
+	instr = nextf + 1;
+
+	/* Field five: get global MLP list. */
+	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
+	if (*nextf != '\0' && *nextf != '#' && !isspace(*nextf)) {
+		*errstrp = (char *)nextf;
+		*errp = LTSNET_ILL_ENTRY;
+		goto err_ret;
+	}
+	if (!parse_mlp_list(&zc->zc_shared_mlp, fieldbuf, errp, errstrp)) {
+		*errstrp = (char *)instr + (*errstrp - fieldbuf);
+		goto err_ret;
+	}
+
+	return (zc);
+
+err_ret:
+	err = errno;
+	tsol_freezcent(zc);
+	errno = err;
+	return (NULL);
+}
+
+void
+tsol_freezcent(tsol_zcent_t *zc)
+{
+	if (zc != NULL) {
+		free(zc->zc_private_mlp);
+		free(zc->zc_shared_mlp);
+		free(zc);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/i386/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+MAPDIR= ../spec/i386
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/sparc/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/sparcv9/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/Makefile
+#
+
+include $(SRC)/lib/Makefile.spec.arch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/Makefile.targ	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/Makefile.targ
+#
+
+LIBRARY= libtsnet.a
+VERS= .1
+
+OBJECTS= tsnet.o
+
+SPECCPP += -I../../
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/amd64/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/i386/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/i386/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/sparc/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/sparc/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/sparcv9/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/tsnet.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,206 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/tsnet.spec
+#
+
+function	tsol_gettpbyname
+include		<libtsnet.h>
+declaration	tsol_tpent_t *tsol_gettpbyname(const char *name);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_gettpent
+include		<libtsnet.h>
+declaration 	tsol_tpent_t *tsol_gettpent(void);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_fgettpent
+include		<libtsnet.h>
+declaration 	tsol_tpent_t *tsol_gettpent(FILE *);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_freetpent
+include		<libtsnet.h>
+declaration 	void tsol_freetpent(tsol_tpent_t *);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_settpent
+include		<libtsnet.h>
+declaration	void tsol_settpent(int stay);
+version		SUNWprivate_1.1
+end
+
+function	tsol_endtpent
+include		<libtsnet.h>
+declaration	void tsol_endtpent(void);
+version		SUNWprivate_1.1
+end
+
+function	str_to_tpstr
+include		<libtsnet.h>
+declaration	int str_to_tpstr(const char *, int, void *, char *, int);
+version		SUNWprivate_1.1
+end
+
+function	tpstr_to_ent
+include		<libtsnet.h>
+declaration	tsol_tpent_t *tpstr_to_ent(tsol_tpstr_t *, int *, char **);
+version		SUNWprivate_1.1
+end
+
+function	tsol_getrhbyaddr
+include		<libtsnet.h>
+declaration	tsol_rhent_t *tsol_getrhbyaddr(const void *addr, size_t len, \
+		    int type);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_getrhent
+include		<libtsnet.h>
+declaration 	tsol_rhent_t *tsol_getrhent(void);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_fgetrhent
+include		<libtsnet.h>
+declaration 	tsol_rhent_t *tsol_getrhent(FILE *);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_freerhent
+include		<libtsnet.h>
+declaration 	void tsol_freerhent(tsol_rhent_t *);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_setrhent
+include		<libtsnet.h>
+declaration	void tsol_setrhent(int stay);
+version		SUNWprivate_1.1
+end
+
+function	tsol_endrhent
+include		<libtsnet.h>
+declaration	void tsol_endrhent(void);
+version		SUNWprivate_1.1
+end
+
+function	str_to_rhstr
+include		<libtsnet.h>
+declaration	int str_to_rhstr(const char *, int, void *, char *, int);
+version		SUNWprivate_1.1
+end
+
+function	rhstr_to_ent
+include		<libtsnet.h>
+declaration	tsol_rhent_t *rhstr_to_ent(tsol_rhstr_t *, int *, char **);
+version		SUNWprivate_1.1
+end
+
+function	tsol_getrhtype
+include		<libtsnet.h>
+declaration	tsol_host_type_t tsol_getrhtype(char *);
+version		SUNWprivate_1.1
+end
+
+function	tsol_sgetzcent
+include		<libtsnet.h>
+declaration	tsol_zcent_t *tsol_sgetzcent(const char *instr, int *errp, \
+		    char **errstrp);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_freezcent
+include		<libtsnet.h>
+declaration 	void tsol_freezcent(tsol_zcent_t *);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	sl_to_str
+include		<libtsnet.h>
+declaration	const char *sl_to_str(const bslabel_t *sl);
+version		SUNWprivate_1.1
+end
+
+function	rtsa_to_str
+include		<libtsnet.h>
+declaration	const char *rtsa_to_str(const struct rtsa_s *rtsa, \
+		    char *line, size_t len);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	rtsa_keyword
+include		<libtsnet.h>
+declaration	boolean_t rtsa_keyword(const char *opt, struct rtsa_s *rtsa, \
+		    int *errp, char **errstr);
+version		SUNWprivate_1.1
+exception	$return == 0
+end
+
+function	tsol_strerror
+include		<libtsnet.h>
+declaration	const char *tsol_strerror(int libtserr, int errnoval);
+version		SUNWprivate_1.1
+end
+
+function	tnrhtp
+include		<libtsnet.h>
+declaration	int tnrhtp(int cmd, tsol_tpent_t *buf);
+version		SUNWprivate_1.1
+errno		ENOSYS EFAULT EINVAL ENOENT EOPNOTSUPP EPERM
+exception	$return == -1
+end
+
+function	tnrh
+include		<libtsnet.h>
+declaration	int tnrh(int cmd, tsol_rhent_t *buf);
+version		SUNWprivate_1.1
+errno		ENOSYS EFAULT EINVAL ENOENT EOPNOTSUPP EPERM ENOMEM
+exception	$return == -1
+end
+
+function	tnmlp
+include		<libtsnet.h>
+declaration	int tnmlp(int cmd, tsol_mlpent_t *buf);
+version		SUNWprivate_1.1
+errno		ENOSYS EFAULT EINVAL ENOENT EEXIST EOPNOTSUPP EPERM
+exception	$return == -1
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsnet/spec/versions	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libtsnet/spec/versions
+#
+
+sparc {
+	SUNWprivate_1.1;
+}
+i386 {
+	SUNWprivate_1.1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,73 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# lib/libtsol/Makefile
+#
+
+include ../Makefile.lib
+
+HDRS =		label.h
+HDRDIR =	common
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+POFILE =	libtsol.po
+MSGFILES =	common/btos.c common/private.c common/stob.c
+XGETFLAGS =	-a
+
+all := 		TARGET = all
+clean :=	TARGET = clean
+clobber :=	TARGET = clobber
+install	:=	TARGET = install
+lint :=		TARGET = lint
+
+.KEEP_STATE:
+
+# Override so that label.h gets installed where expected.
+ROOTHDRDIR=	$(ROOT)/usr/include/tsol
+
+all clean clobber install: spec .WAIT $(SUBDIRS)
+
+lint:	$(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(POFILE):	$(MSGFILES)
+		$(BUILDPO.msgfiles)
+
+_msg:		$(MSGDOMAINPOFILE)
+
+$(SUBDIRS) spec:	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,74 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# lib/libtsol/Makefile.com
+#
+
+LIBRARY =	libtsol.a
+VERS =		.2
+
+OBJECTS = \
+	blabel.o btohex.o btos.o call_labeld.o \
+	getlabel.o getplabel.o hextob.o \
+	ltos.o misc.o getpathbylabel.o private.o privlib.o \
+	setflabel.o stob.o stol.o zone.o
+
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+$(LINTLIB):=	SRCS = $(SRCDIR)/$(LINTSRC)
+LDLIBS +=	-lsecdb -lc
+
+NONCOMMON =	$(OBJECTS:blabel.o=)
+lint:=		SRCS = $(NONCOMMON:%.o=$(SRCDIR)/%.c) $(COMMONDIR)/blabel.c
+
+SRCDIR =	../common
+MAPDIR =	../spec/$(TRANSMACH)
+SPECMAPFILE =	$(MAPDIR)/mapfile
+
+COMMONDIR=	$(SRC)/common/tsol
+
+CFLAGS +=	$(CCVERBOSE)
+CPPFLAGS +=	-D_REENTRANT -I$(SRCDIR) -I$(COMMONDIR)
+
+LINTFLAGS64 +=	-Xarch=v9
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+objs/%.o pic_profs/%.o pics/%.o:	$(COMMONDIR)/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/amd64/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/btohex.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,200 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *      btohex.c - Binary to Hexadecimal string conversion.
+ *
+ *		These routines convert binary labels into canonical
+ *	hexadecimal representations of the binary form.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
+/* 0x + Classification + '-' + ll + '-' + Compartments + end of string */
+#define	_HEX_SIZE 2+(sizeof (Classification_t)*2)+4+\
+	(sizeof (Compartments_t)*2)+1
+
+static char hex_buf[_HEX_SIZE];
+
+/*
+ *	h_alloc - Allocate data storage for a Hexadecimal label string.
+ *
+ *	Entry	id = Type of label to allocate storage for.
+ *		     SUN_SL_ID  - Sensitivity Label.
+ *		     SUN_CLR_ID - Clearance.
+ *
+ *	Returns	NULL, If unable to allocate storage.
+ *		Address of buffer.
+ *
+ *	Calls	malloc;
+ */
+
+char *
+h_alloc(unsigned char id)
+{
+	size_t size;
+
+	switch (id) {
+
+	case SUN_SL_ID:
+		size = _HEX_SIZE;
+		break;
+
+	case SUN_CLR_ID:
+		size = _HEX_SIZE;
+		break;
+
+	default:
+		return (NULL);
+	}
+
+	return ((char *)malloc(size));
+}
+
+
+/*
+ *	h_free - Free a Hexadecimal label string.
+ *
+ *	Entry	hex = Hexadecimal label string.
+ *
+ *	Returns	none.
+ *
+ *	Calls	free.
+ */
+
+void
+h_free(char *hex)
+{
+
+	if (hex == NULL)
+		return;
+
+	free(hex);
+}
+
+
+/*
+ *	bsltoh_r - Convert a Sensitivity Label into a Hexadecimal label string.
+ *
+ *	Entry	label = Sensitivity Label to be translated.
+ *		hex = Buffer to place converted label.
+ *		len = Length of buffer.
+ *
+ *	Returns	NULL, If invalid label type.
+ *		Address of buffer.
+ *
+ *	Calls	label_to_str, strncpy.
+ */
+
+char *
+bsltoh_r(const m_label_t *label, char *hex)
+{
+	char *h;
+
+	if (label_to_str(label, &h, M_INTERNAL, DEF_NAMES) != 0) {
+		free(h);
+		return (NULL);
+	}
+
+	(void) strncpy(hex, (const char *)h, _HEX_SIZE);
+	free(h);
+	return (hex);
+}
+
+
+/*
+ *	bsltoh - Convert a Sensitivity Label into a Hexadecimal label string.
+ *
+ *	Entry	label = Sensitivity Label to be translated.
+ *
+ *	Returns	NULL, If invalid label type.
+ *		Address of statically allocated hex label string.
+ *
+ *	Calls	bsltoh_r.
+ *
+ *	Uses	hex_buf.
+ */
+
+char *
+bsltoh(const m_label_t *label)
+{
+
+	return (bsltoh_r(label, hex_buf));
+}
+
+
+/*
+ *	bcleartoh_r - Convert a Clearance into a Hexadecimal label string.
+ *
+ *	Entry	clearance = Clearance to be translated.
+ *		hex = Buffer to place converted label.
+ *		len = Length of buffer.
+ *
+ *	Returns	NULL, If invalid label type.
+ *		Address of buffer.
+ *
+ *	Calls	label_to_str, strncpy.
+ */
+
+char *
+bcleartoh_r(const m_label_t *clearance, char *hex)
+{
+	char *h;
+
+	if (label_to_str(clearance, &h, M_INTERNAL, DEF_NAMES) != 0) {
+		free(h);
+		return (NULL);
+	}
+
+	(void) strncpy(hex, (const char *)h, _HEX_SIZE);
+	free(h);
+	return (hex);
+}
+
+
+/*
+ *	bcleartoh - Convert a Clearance into a Hexadecimal label string.
+ *
+ *	Entry	clearance = Clearance to be translated.
+ *
+ *	Returns	NULL, If invalid label type.
+ *		Address of statically allocated hex label string.
+ *
+ *	Calls	bcleartoh_r.
+ *
+ *	Uses	hex_buf.
+ */
+
+char *
+bcleartoh(const m_label_t *clearance)
+{
+
+	return (bcleartoh_r(clearance, hex_buf));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/btos.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,485 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *      Binary label to label string translations.
+ */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <wchar.h>
+
+#include <sys/mman.h>
+
+#include <tsol/label.h>
+
+#include "clnt.h"
+#include "labeld.h"
+#include <sys/tsol/label_macro.h>
+
+#if	!defined(TEXT_DOMAIN)		/* should be defined by Makefiles */
+#define	TEXT_DOMAIN "SYS_TEST"
+#endif	/* TEXT_DOMAIN */
+
+static bslabel_t slow;	/* static admin_low high sensitivity label */
+static bslabel_t shigh;	/* static admin_high sensitivity label */
+static bclear_t clrlow, clrhigh; /* static admin_low and admin_high Clearance */
+
+static char	*sstring;	/* return string for sb*tos */
+static size_t	ssize;		/* current size of return string */
+
+static int
+return_string(char **string, int str_len, char *val)
+{
+	char	*cpyptr;
+	size_t	val_len = strlen(val) + 1;
+
+	if (*string == NULL) {
+		if ((*string = malloc(val_len)) == NULL)
+			return (0);
+	} else if (val_len > str_len) {
+		**string = '\0';
+		return (0);
+	}
+
+	cpyptr = *string;
+	bcopy(val, cpyptr, val_len);
+
+	return (val_len);
+}
+
+void
+set_label_view(uint_t *callflags, uint_t flags)
+{
+	if (flags&VIEW_INTERNAL) {
+		*callflags |= LABELS_VIEW_INTERNAL;
+	} else if (flags&VIEW_EXTERNAL) {
+		*callflags |= LABELS_VIEW_EXTERNAL;
+	}
+}
+
+int
+alloc_string(char **string, size_t size, char val)
+{
+	if (*string == NULL) {
+		if ((*string = malloc(ALLOC_CHUNK)) == NULL)
+			return (0);
+	} else {
+		if ((*string = realloc(*string, size + ALLOC_CHUNK)) == NULL) {
+			**string = val;
+			return (0);
+		}
+	}
+	**string = val;
+	return (ALLOC_CHUNK);
+}
+
+#define	slcall callp->param.acall.cargs.bsltos_arg
+#define	slret callp->param.aret.rvals.bsltos_ret
+/*
+ *	bsltos - Convert Binary Sensitivity Label to Sensitivity Label string.
+ *
+ *	Entry	label = Binary Sensitivity Label to be converted.
+ *		string = NULL ((char *) 0), if memory to be allocated,
+ *			 otherwise, pointer to preallocated memory.
+ *		str_len = Length of preallocated memory, else ignored.
+ *		flags = Logical sum of:
+ *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
+ *				LONG_WORDS or SHORT_WORDS,
+ *				VIEW_INTERNAL or VIEW_EXTERNAL, and
+ *				NO_CLASSIFICATION.
+ *			LONG_CLASSIFICATION, use long classification names.
+ *			SHORT_CLASSIFICATION, use short classification
+ *						names (default).
+ *			NO_CLASSIFICATION, don't translate classification.
+ *			LONG_WORDS, use the long form of words (default).
+ *			SHORTWORDS, use the short form of words where available.
+ *			VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = Sensitivity Label string, or empty string if
+ *			 not enough preallocated memory.
+ *
+ *	Returns	-1, If unable to access label encodings database.
+ *		 0, If unable to allocate string,
+ *			or allocated string to short
+ *			(and **string = '\0').
+ *		length (including null) of Sensitivity Label string,
+ *			If successful.
+ *
+ *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
+ *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
+ *			clnt_perror, malloc, strcat, strlen.
+ *
+ *	Uses	ADMIN_HIGH, ADMIN_LOW, shigh, slow.
+ */
+
+ssize_t
+bsltos(const bslabel_t *label, char **string, size_t str_len,
+    int flags)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bsltos_call_t, 0);
+	int	rval;
+
+	if (!BLTYPE(label, SUN_SL_ID)) {
+		return (-1);
+	}
+
+	call.callop = BSLTOS;
+	slcall.label = *label;
+	slcall.flags = (flags&NO_CLASSIFICATION) ? LABELS_NO_CLASS : 0;
+	slcall.flags |= (flags&SHORT_CLASSIFICATION ||
+	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
+	slcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
+	    LABELS_SHORT_WORDS : 0;
+	set_label_view(&slcall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
+
+		if (callp->reterr != 0)
+			return (-1);
+
+		/* unpack Sensitivity Label */
+
+		rval = return_string(string, str_len, slret.slabel);
+
+		if (callp != &call)
+			(void) munmap((void *)callp, bufsize);
+		return (rval);
+	} else if (rval == NOSERVER) {
+		/* server not present */
+		/* special case admin_high and admin_low */
+
+		if (!BLTYPE(&slow, SUN_SL_ID)) {
+			/* initialize static labels */
+
+			BSLLOW(&slow);
+			BSLHIGH(&shigh);
+		}
+
+		if (BLEQUAL(label, &slow)) {
+			return (return_string(string, str_len, ADMIN_LOW));
+		} else if (BLEQUAL(label, &shigh)) {
+			return (return_string(string, str_len, ADMIN_HIGH));
+		}
+	}
+	return (-1);
+}  /* bsltos */
+#undef	slcall
+#undef	slret
+
+#define	clrcall callp->param.acall.cargs.bcleartos_arg
+#define	clrret callp->param.aret.rvals.bcleartos_ret
+/*
+ *	bcleartos - Convert Binary Clearance to Clearance string.
+ *
+ *	Entry	clearance = Binary Clearance to be converted.
+ *		string = NULL ((char *) 0), if memory to be allocated,
+ *			 otherwise, pointer to preallocated memory.
+ *		str_len = Length of preallocated memory, else ignored.
+ *		flags = Logical sum of:
+ *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
+ *				LONG_WORDS or SHORT_WORDS,
+ *				VIEW_INTERNAL or VIEW_EXTERNAL.
+ *			LONG_CLASSIFICATION, use long classification names.
+ *			SHORT_CLASSIFICATION, use short classification
+ *						names (default).
+ *			LONG_WORDS, use the long form of words (default).
+ *			SHORTWORDS, use the short form of words where available.
+ *			VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = Clearance string, or empty string if not
+ *			enough preallocated memory.
+ *
+ *	Returns	-1, If unable to access label encodings database.
+ *		 0, If unable to allocate string,
+ *			or allocated string to short
+ *			(and **string = '\0').
+ *		length (including null) of Clearance string,
+ *			If successful.
+ *
+ *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
+ *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
+ *			clnt_perror, malloc, strcat, strlen.
+ *
+ *	Uses	ADMIN_HIGH, ADMIN_LOW, clrhigh, clrlow.
+ */
+
+ssize_t
+bcleartos(const bclear_t *clearance, char **string, size_t str_len,
+    int flags)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bcleartos_call_t, 0);
+	int	rval;
+
+	if (!BLTYPE(clearance, SUN_CLR_ID)) {
+		return (-1);
+	}
+
+	call.callop = BCLEARTOS;
+	clrcall.clear = *clearance;
+	clrcall.flags = (flags&SHORT_CLASSIFICATION ||
+	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
+	clrcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
+	    LABELS_SHORT_WORDS : 0;
+	set_label_view(&clrcall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
+
+		if (callp->reterr != 0)
+			return (-1);
+
+		/* unpack Clearance */
+
+		rval = return_string(string, str_len, clrret.cslabel);
+
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (rval);
+	} else if (rval == NOSERVER) {
+		/* server not present */
+		/* special case admin_high and admin_low */
+
+		if (!BLTYPE(&clrlow, SUN_CLR_ID)) {
+			/* initialize static labels */
+
+			BCLEARLOW(&clrlow);
+			BCLEARHIGH(&clrhigh);
+		}
+		if (BLEQUAL(clearance, &clrlow)) {
+			return (return_string(string, str_len, ADMIN_LOW));
+		} else if (BLEQUAL(clearance, &clrhigh)) {
+			return (return_string(string, str_len, ADMIN_HIGH));
+		}
+	}
+	return (-1);
+}  /* bcleartos */
+#undef	clrcall
+#undef	clrret
+
+/*
+ *	sbsltos - Convert Sensitivity Label to canonical clipped form.
+ *
+ *	Entry	label = Sensitivity Label to be converted.
+ *		len = Maximum length of translated string, excluding NULL.
+ *		      0, full string.
+ *		sstring = address of string to translate into.
+ *		ssize = size of memory currently allocated to sstring.
+ *
+ *	Exit	sstring = Newly translated string.
+ *		ssize = Updated if more memory pre-allocated.
+ *
+ *	Returns	NULL, If error, len too small, unable to translate, or get
+ *		      memory for string.
+ *		Address of string containing converted value.
+ *
+ *	Calls	alloc_string, bsltos, strcpy.
+ *
+ *	Uses	ssize, sstring.
+ */
+
+char *
+sbsltos(const bslabel_t *label, size_t len)
+{
+	ssize_t	slen;		/* length including NULL */
+	wchar_t *wstring;
+	int	wccount;
+
+	if (ssize == 0) {
+		/* Allocate string memory. */
+		if ((ssize = alloc_string(&sstring, ssize, 's')) == 0)
+			/* can't get initial memory for string */
+			return (NULL);
+	}
+
+again:
+	if ((slen = bsltos(label, &sstring, ssize,
+	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
+		/* error in translation */
+		if (slen == 0) {
+			if (*sstring == '\0') {
+				int newsize;
+				/* sstring not long enough */
+				if ((newsize = alloc_string(&sstring, ssize,
+				    's')) == 0) {
+					/* Can't get more memory */
+					return (NULL);
+				}
+				ssize += newsize;
+				goto again;
+			}
+		}
+		return (NULL);
+	}
+	if (len == 0) {
+		return (sstring);
+	} else if (len < MIN_SL_LEN) {
+		return (NULL);
+	}
+	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
+		return (NULL);
+	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
+		free(wstring);
+		return (NULL);
+	}
+	if (wccount > len) {
+		wchar_t *clipp = wstring + (len - 2);
+
+		/* Adjust string size to desired length */
+
+		clipp[0] = L'<';
+		clipp[1] = L'-';
+		clipp[2] = L'\0';
+
+		while (wcstombs(NULL, wstring, 0) >= ssize) {
+			int newsize;
+
+			/* sstring not long enough */
+			if ((newsize = alloc_string(&sstring, ssize, 's')) ==
+			    0) {
+				/* Can't get more memory */
+				return (NULL);
+			}
+			ssize += newsize;
+		}
+
+		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
+			free(wstring);
+			return (NULL);
+		}
+	}
+	free(wstring);
+
+	return (sstring);
+}  /* sbsltos */
+
+/*
+ *	sbcleartos - Convert Clearance to canonical clipped form.
+ *
+ *	Entry	clearance = Clearance to be converted.
+ *		len = Maximum length of translated string, excluding NULL.
+ *		      0, full string.
+ *		sstring = address of string to translate into.
+ *		ssize = size of memory currently allocated to sstring.
+ *
+ *	Exit	sstring = Newly translated string.
+ *		ssize = Updated if more memory pre-allocated.
+ *
+ *	Returns	NULL, If error, len too small, unable to translate, or get
+ *		      memory for string.
+ *		Address of string containing converted value.
+ *
+ *	Calls	alloc_string, bcleartos, strcpy.
+ *
+ *	Uses	ssize, sstring.
+ */
+
+char *
+sbcleartos(const bclear_t *clearance, size_t len)
+{
+	ssize_t	slen;		/* length including NULL */
+	wchar_t *wstring;
+	int	wccount;
+
+	if (ssize == 0) {
+		/* Allocate string memory. */
+		if ((ssize = alloc_string(&sstring, ssize, 'c')) == 0)
+			/* can't get initial memory for string */
+			return (NULL);
+	}
+
+again:
+	if ((slen = bcleartos(clearance, &sstring, ssize,
+	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
+		/* error in translation */
+		if (slen == 0) {
+			if (*sstring == '\0') {
+				int newsize;
+				/* sstring not long enough */
+				if ((newsize = alloc_string(&sstring, ssize,
+				    'c')) == 0) {
+					/* Can't get more memory */
+					return (NULL);
+				}
+				ssize += newsize;
+				goto again;
+			}
+		}
+		return (NULL);
+	}
+	if (len == 0) {
+		return (sstring);
+	} else if (len < MIN_CLR_LEN) {
+		return (NULL);
+	}
+	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
+		return (NULL);
+	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
+		free(wstring);
+		return (NULL);
+	}
+	if (wccount > len) {
+		wchar_t *clipp = wstring + (len - 2);
+
+		/* Adjust string size to desired length */
+
+		clipp[0] = L'<';
+		clipp[1] = L'-';
+		clipp[2] = L'\0';
+
+		while (wcstombs(NULL, wstring, 0) >= ssize) {
+			int newsize;
+
+			/* sstring not long enough */
+			if ((newsize = alloc_string(&sstring, ssize, 'c')) ==
+			    0) {
+				/* Can't get more memory */
+				free(wstring);
+				return (NULL);
+			}
+			ssize += newsize;
+		}
+		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
+			free(wstring);
+			return (NULL);
+		}
+	}
+	free(wstring);
+
+	return (sstring);
+}  /* sbcleartos */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/call_labeld.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,308 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "labeld.h"
+
+#ifndef	DEBUG
+#define	perror(e)
+#endif	/* !DEBUG */
+
+/*
+ *	Library prototypes to get away from lots of static build problems.
+ */
+
+extern int __nanosleep(const struct timespec *, struct timespec *);
+
+/*
+ *	This is cloned from _nsc_trydoorcall used by the nscd client.
+ *
+ * Routine that actually performs the door call.
+ * Note that we cache a file descriptor.  We do
+ * the following to prevent disasters:
+ *
+ * 1) Never use 0, 1 or 2; if we get this from the open
+ *    we dup it upwards.
+ *
+ * 2) Set the close on exec flags so descriptor remains available
+ *    to child processes.
+ *
+ * 3) Verify that the door is still the same one we had before
+ *    by using door_info on the client side.
+ *
+ *	Note that we never close the file descriptor if it isn't one
+ *	we allocated; we check this with door info.  The rather tricky
+ *	logic is designed to be fast in the normal case (fd is already
+ *	allocated and is ok) while handling the case where the application
+ *	closed it underneath us or where the nscd dies or re-execs itself
+ *	and we're a multi-threaded application.  Note that we cannot protect
+ *	the application if it closes the fd and it is multi-threaded.
+ *
+ *  int __call_labeld(label_door_op **dptr, int *ndata, int *adata);
+ *
+ *      *dptr	IN: points to arg buffer OUT: points to results buffer
+ *      *ndata	IN: overall size of buffer OUT: overall size of buffer
+ *      *adata	IN: size of call data OUT: size of return data
+ *
+ *  Note that *dptr may change if provided space as defined by *bufsize is
+ *  inadequate.  In this case the door call mmaps more space and places
+ *  the answer there and sets dptr to contain a pointer to the space, which
+ *  should be freed with munmap.
+ *
+ *  Returns 0 if the door call reached the server, -1 if contact was not made.
+ *
+ */
+
+
+static mutex_t	_door_lock = DEFAULTMUTEX;
+
+int
+__call_labeld(labeld_data_t **dptr, size_t *ndata, size_t *adata)
+{
+	static	int 		doorfd = -1;
+	static	door_info_t 	real_door;
+	struct stat		st;
+	door_info_t 		my_door;
+	door_arg_t		param;
+	char			door_name[MAXPATHLEN];
+	struct timespec		ts;
+	int			busy = 0;	/* number of busy loops */
+
+#ifdef	DEBUG
+	labeld_data_t		*callptr = *dptr;
+	int			buf_size = *ndata;
+	int			return_size = *adata;
+#endif	/* DEBUG */
+
+	/*
+	 * the first time in we try and open and validate the door.
+	 * the validations are that the door must have been
+	 * created with the label service door cookie and
+	 * that it has the same door ID.  If any of these
+	 * validations fail we refuse to use the door.
+	 */
+	ts.tv_sec = 0;		/* initialize nanosecond retry timer */
+	ts.tv_nsec = 100;
+	(void) mutex_lock(&_door_lock);
+
+try_again:
+	if (doorfd == -1) {
+		int	tbc[3];
+		int	i;
+
+		(void) snprintf(door_name, sizeof (door_name), "%s%s",
+		    DOOR_PATH, DOOR_NAME);
+		if ((doorfd = open64(door_name, O_RDONLY, 0)) < 0) {
+			(void) mutex_unlock(&_door_lock);
+			perror("server door open");
+			return (NOSERVER);
+		}
+
+		/*
+		 * dup up the file descriptor if we have 0 - 2
+		 * to avoid problems with shells stdin/out/err
+		 */
+		i = 0;
+		while (doorfd < 3) { /* we have a reserved fd */
+			tbc[i++] = doorfd;
+			if ((doorfd = dup(doorfd)) < 0) {
+				perror("couldn't dup");
+				while (i--)
+				    (void) close(tbc[i]);
+				doorfd = -1;
+				(void) mutex_unlock(&_door_lock);
+				return (NOSERVER);
+			}
+		}
+		while (i--)
+		    (void) close(tbc[i]);
+
+		/*
+		 * mark this door descriptor as close on exec
+		 */
+		(void) fcntl(doorfd, F_SETFD, FD_CLOEXEC);
+		if (door_info(doorfd, &real_door) < 0) {
+			/*
+			 * we should close doorfd because we just opened it
+			 */
+			perror("real door door_info");
+			(void) close(doorfd);
+			doorfd = -1;
+			(void) mutex_unlock(&_door_lock);
+			return (NOSERVER);
+		}
+		if (fstat(doorfd, &st) < 0) {
+			perror("real door fstat");
+			return (NOSERVER);
+		}
+#ifdef	DEBUG
+		(void) printf("\treal door %s\n", door_name);
+		(void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid,
+		    st.st_gid, st.st_mode);
+		(void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1);
+		(void) printf("\t\t pid = %d\n", real_door.di_target);
+		(void) printf("\t\t procedure = %llx\n", real_door.di_proc);
+		(void) printf("\t\t cookie = %llx\n",  real_door.di_data);
+		(void) printf("\t\t attributes = %x\n",
+		    real_door.di_attributes);
+		if (real_door.di_attributes & DOOR_UNREF)
+			(void) printf("\t\t\t UNREF\n");
+		if (real_door.di_attributes & DOOR_PRIVATE)
+			(void) printf("\t\t\t PRIVATE\n");
+		if (real_door.di_attributes & DOOR_LOCAL)
+			(void) printf("\t\t\t LOCAL\n");
+		if (real_door.di_attributes & DOOR_REVOKED)
+			(void) printf("\t\t\t REVOKED\n");
+		if (real_door.di_attributes & DOOR_DESCRIPTOR)
+			(void) printf("\t\t\t DESCRIPTOR\n");
+		if (real_door.di_attributes & DOOR_RELEASE)
+			(void) printf("\t\t\t RELEASE\n");
+		if (real_door.di_attributes & DOOR_DELAY)
+			(void) printf("\t\t\t DELAY\n");
+		(void) printf("\t\t id = %llx\n", real_door.di_uniquifier);
+#endif	/* DEBUG */
+		if ((real_door.di_attributes & DOOR_REVOKED) ||
+		    (real_door.di_data != (door_ptr_t)COOKIE)) {
+#ifdef	DEBUG
+			(void) printf("real door revoked\n");
+#endif	/* DEBUG */
+			(void) close(doorfd);
+			doorfd = -1;
+			(void) mutex_unlock(&_door_lock);
+			return (NOSERVER);
+		}
+	} else {
+		if ((door_info(doorfd, &my_door) < 0) ||
+		    (my_door.di_data != (door_ptr_t)COOKIE) ||
+			(my_door.di_uniquifier != real_door.di_uniquifier)) {
+			perror("my door door_info");
+			/*
+			 * don't close it - someone else has clobbered fd
+			 */
+			doorfd = -1;
+			goto try_again;
+		}
+		if (fstat(doorfd, &st) < 0) {
+			perror("my door fstat");
+			goto try_again;
+		}
+#ifdef	DEBUG
+		(void) sprintf(door_name, "%s%s", DOOR_PATH, DOOR_NAME);
+		(void) printf("\tmy door %s\n", door_name);
+		(void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid,
+		    st.st_gid, st.st_mode);
+		(void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1);
+		(void) printf("\t\t pid = %d\n", my_door.di_target);
+		(void) printf("\t\t procedure = %llx\n", my_door.di_proc);
+		(void) printf("\t\t cookie = %llx\n",  my_door.di_data);
+		(void) printf("\t\t attributes = %x\n", my_door.di_attributes);
+		if (my_door.di_attributes & DOOR_UNREF)
+			(void) printf("\t\t\t UNREF\n");
+		if (my_door.di_attributes & DOOR_PRIVATE)
+			(void) printf("\t\t\t PRIVATE\n");
+		if (my_door.di_attributes & DOOR_LOCAL)
+			(void) printf("\t\t\t LOCAL\n");
+		if (my_door.di_attributes & DOOR_REVOKED)
+			(void) printf("\t\t\t REVOKED\n");
+		if (my_door.di_attributes & DOOR_DESCRIPTOR)
+			(void) printf("\t\t\t DESCRIPTOR\n");
+		if (my_door.di_attributes & DOOR_RELEASE)
+			(void) printf("\t\t\t RELEASE\n");
+		if (my_door.di_attributes & DOOR_DELAY)
+			(void) printf("\t\t\t DELAY\n");
+		(void) printf("\t\t id = %llx\n", my_door.di_uniquifier);
+#endif	/* DEBUG */
+		if (my_door.di_attributes & DOOR_REVOKED) {
+#ifdef	DEBUG
+			(void) printf("my door revoked\n");
+#endif	/* DEBUG */
+			(void) close(doorfd);	/* labeld exited .... */
+			doorfd = -1;	/* try and restart connection */
+			goto try_again;
+		}
+	}
+	(void) mutex_unlock(&_door_lock);
+
+	param.data_ptr = (char *)*dptr;
+	param.data_size = *adata;
+	param.desc_ptr = NULL;
+	param.desc_num = 0;
+	param.rbuf = (char *)*dptr;
+	param.rsize = *ndata;
+
+	if (door_call(doorfd, &param) < 0) {
+		if (errno == EAGAIN && busy++ < 10) {
+			/* adjust backoff */
+			if ((ts.tv_nsec *= 10) >= NANOSEC) {
+				ts.tv_sec++;
+				ts.tv_nsec = 100;
+			}
+			(void) __nanosleep(&ts, NULL);
+#ifdef	DEBUG
+			(void) printf("door_call failed EAGAIN # %d\n", busy);
+#endif	/* DEBUG */
+			(void) mutex_lock(&_door_lock);
+			goto try_again;
+		}
+		perror("door call");
+		return (NOSERVER);
+	}
+
+	*adata = (int)param.data_size;
+	*ndata = (int)param.rsize;
+	/*LINTED*/
+	*dptr = (labeld_data_t *)param.data_ptr;
+
+	if (*adata == 0 || *dptr == NULL) {
+#ifdef	DEBUG
+		(void) printf("\tNo data returned, size = %lu, dptr = %p\n",
+		    (unsigned long)*adata, (void *)*dptr);
+#endif	/* DEBUG */
+		return (NOSERVER);
+	}
+#ifdef	DEBUG
+	(void) printf("call buf = %x, buf size  = %d, call size = %d\n",
+	    callptr, buf_size, return_size);
+	(void) printf("retn buf = %x, buf size  = %d, retn size = %d\n",
+	    *dptr, *ndata, *adata);
+	(void) printf("\treply status = %d\n", (*dptr)->param.aret.ret);
+#endif	/* DEBUG */
+	return ((*dptr)->param.aret.ret);
+
+}  /* __call_labeld */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/clnt.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,49 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CLNT_H
+#define	_CLNT_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	MAXCOLOR	256	/* Max size of a static color string */
+#define	MIN_CMW_LEN	8	/* minimum length of clipped CMW Label */
+#define	MIN_SL_LEN	3	/* minimum length of clipped SL */
+#define	MIN_IL_LEN	3	/* minimum length of clipped IL */
+#define	MIN_CLR_LEN	3	/* minimum length of clipped Clearance */
+
+#define	ALLOC_CHUNK	1024	/* size of chunk for sb*tos allocs */
+
+extern int alloc_string(char **, size_t, char);
+extern void set_label_view(uint_t *, uint_t);
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _CLNT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/getlabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,66 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	String to binary label translations.
+ */
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
+#include <sys/syscall.h>
+#include <sys/tsol/tsyscall.h>
+
+#include <sys/types.h>
+
+/*
+ * getlabel(3TSOL) - get file label
+ *
+ * This is the library interface to the system call.
+ */
+
+int
+getlabel(const char *path, bslabel_t *label)
+{
+	return (syscall(SYS_labelsys, TSOL_GETLABEL, path, label));
+}
+
+/*
+ * fgetlabel(3TSOL) - get file label
+ *
+ * This is the library interface to the system call.
+ */
+int
+fgetlabel(int fd, bslabel_t *label)
+{
+	return (syscall(SYS_labelsys, TSOL_FGETLABEL, fd, label));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/getpathbylabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,503 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+
+/*
+ *	Name:		getpathbylabel.c
+ *
+ *	Description:	Returns the global zone pathname corresponding
+ *			to the specified label. The pathname does
+ *			not need to match an existing file system object.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <tsol/label.h>
+#include <stdlib.h>
+#include <zone.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <stdarg.h>
+
+/*
+ * This structure is used to chain mntent structures into a list
+ * and to cache stat information for each member of the list.
+ */
+struct mntlist {
+	struct mnttab	*mntl_mnt;
+	struct mntlist	*mntl_next;
+};
+
+
+/*
+ * Return a pointer to the trailing suffix of full that follows the prefix
+ * given by pref.  If pref isn't a prefix of full, return NULL.  Apply
+ * pathname semantics to the prefix test, so that pref must match at a
+ * component boundary.
+ */
+static char *
+pathsuffix(char *full, char *pref)
+{
+	int preflen;
+
+	if (full == NULL || pref == NULL)
+		return (NULL);
+
+	preflen = strlen(pref);
+	if (strncmp(pref, full, preflen) != 0)
+		return (NULL);
+
+	/*
+	 * pref is a substring of full.  To be a subpath, it cannot cover a
+	 * partial component of full.  The last clause of the test handles the
+	 * special case of the root.
+	 */
+	if (full[preflen] != '\0' && full[preflen] != '/' && preflen > 1)
+		return (NULL);
+
+	if (preflen == 1 && full[0] == '/')
+		return (full);
+	else
+		return (full + preflen);
+}
+
+/*
+ * Return zero iff the path named by sub is a leading subpath
+ * of the path named by full.
+ *
+ * Treat null paths as matching nothing.
+ */
+static int
+subpath(char *full, char *sub)
+{
+	return (pathsuffix(full, sub) == NULL);
+}
+
+static void
+tsol_mnt_free(struct mnttab *mnt)
+{
+	if (mnt->mnt_special)
+		free(mnt->mnt_special);
+	if (mnt->mnt_mountp)
+		free(mnt->mnt_mountp);
+	if (mnt->mnt_fstype)
+		free(mnt->mnt_fstype);
+	if (mnt->mnt_mntopts)
+		free(mnt->mnt_mntopts);
+	free(mnt);
+}
+
+static void
+tsol_mlist_free(struct mntlist *mlist)
+{
+	struct mntlist *mlp;
+
+	for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
+		struct mnttab *mnt = mlp->mntl_mnt;
+
+		if (mnt)
+			tsol_mnt_free(mnt);
+		free(mlp);
+	}
+}
+
+static struct mnttab *
+mntdup(struct mnttab *mnt)
+{
+	struct mnttab *new;
+
+	new = (struct mnttab *)malloc(sizeof (*new));
+	if (new == NULL)
+		return (NULL);
+
+	new->mnt_special = NULL;
+	new->mnt_mountp = NULL;
+	new->mnt_fstype = NULL;
+	new->mnt_mntopts = NULL;
+
+	new->mnt_special = strdup(mnt->mnt_special);
+	if (new->mnt_special == NULL) {
+		tsol_mnt_free(new);
+		return (NULL);
+	}
+	new->mnt_mountp = strdup(mnt->mnt_mountp);
+	if (new->mnt_mountp == NULL) {
+		tsol_mnt_free(new);
+		return (NULL);
+	}
+	new->mnt_fstype = strdup(mnt->mnt_fstype);
+	if (new->mnt_fstype == NULL) {
+		tsol_mnt_free(new);
+		return (NULL);
+	}
+	new->mnt_mntopts = strdup(mnt->mnt_mntopts);
+	if (new->mnt_mntopts == NULL) {
+		tsol_mnt_free(new);
+		return (NULL);
+	}
+	return (new);
+}
+
+static struct mntlist *
+tsol_mkmntlist(void)
+{
+	FILE *mounted;
+	struct mntlist *mntl;
+	struct mntlist *mntst = NULL;
+	struct mnttab mnt;
+
+	if ((mounted = fopen(MNTTAB, "r")) == NULL) {
+		perror(MNTTAB);
+		return (NULL);
+	}
+	resetmnttab(mounted);
+	while (getmntent(mounted, &mnt) == NULL) {
+		mntl = (struct mntlist *)malloc(sizeof (*mntl));
+		if (mntl == NULL) {
+			tsol_mlist_free(mntst);
+			mntst = NULL;
+			break;
+		}
+		mntl->mntl_mnt = mntdup((struct mnttab *)(&mnt));
+		if (mntl->mntl_mnt == NULL) {
+			tsol_mlist_free(mntst);
+			mntst = NULL;
+			break;
+		}
+		mntl->mntl_next = mntst;
+		mntst = mntl;
+	}
+	(void) fclose(mounted);
+	return (mntst);
+}
+
+/*
+ * This function attempts to convert local zone NFS mounted pathnames
+ * into equivalent global zone NFS mounted pathnames. At present
+ * it only works for automounted filesystems. It depends on the
+ * assumption that both the local and global zone automounters
+ * share the same nameservices. It also assumes that any automount
+ * map used by a local zone is available to the global zone automounter.
+ *
+ * The algorithm used consists of three phases.
+ *
+ * 1. The local zone's mnttab is searched to find the automount map
+ *    with the closest matching mountpath.
+ *
+ * 2. The matching autmount map name is looked up in the global zone's
+ *    mnttab to determine the path where it should be mounted in the
+ *    global zone.
+ *
+ * 3. A pathname covered by an appropiate autofs trigger mount in
+ *    the global zone is generated as the resolved pathname
+ *
+ * Among the things that can go wrong is that global zone doesn't have
+ * a matching automount map or the mount was not done via the automounter.
+ * Either of these cases return a NULL path.
+ */
+#define	ZONE_OPT "zone="
+static int
+getnfspathbyautofs(struct mntlist *mlist, zoneid_t zoneid,
+    struct mnttab *autofs_mnt, char *globalpath, char *zonepath, int global_len)
+{
+	struct mntlist *mlp;
+	char zonematch[ZONENAME_MAX + 20];
+	char zonename[ZONENAME_MAX];
+	int  longestmatch;
+	struct	mnttab	*mountmatch;
+
+	if (autofs_mnt) {
+		mountmatch = autofs_mnt;
+		longestmatch = strlen(mountmatch->mnt_mountp);
+	} else {
+		/*
+		 * First we need to get the zonename to look for
+		 */
+		if (zone_getattr(zoneid, ZONE_ATTR_NAME, zonename,
+		    ZONENAME_MAX) == -1) {
+			return (0);
+		}
+
+		(void) strncpy(zonematch, ZONE_OPT, sizeof (zonematch));
+		(void) strlcat(zonematch, zonename, sizeof (zonematch));
+
+		/*
+		 * Find the best match for an automount map that
+		 * corresponds to the local zone's pathname
+		 */
+		longestmatch = 0;
+		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
+			struct mnttab *mnt = mlp->mntl_mnt;
+			int	len;
+			int	matchfound;
+			char	*token;
+			char	*lasts;
+			char	mntopts[MAXPATHLEN];
+
+			if (subpath(globalpath, mnt->mnt_mountp) != 0)
+				continue;
+			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
+				continue;
+
+			matchfound = 0;
+			(void) strncpy(mntopts, mnt->mnt_mntopts, MAXPATHLEN);
+			if ((token = strtok_r(mntopts, ",", &lasts)) != NULL) {
+				if (strcmp(token, zonematch) == 0) {
+					matchfound = 1;
+				} else while ((token = strtok_r(NULL, ",",
+				    &lasts)) != NULL) {
+					if (strcmp(token, zonematch) == 0) {
+						matchfound = 1;
+						break;
+					}
+				}
+			}
+			if (matchfound) {
+				len = strlen(mnt->mnt_mountp);
+				if (len > longestmatch) {
+					mountmatch = mnt;
+					longestmatch = len;
+				}
+			}
+		}
+	}
+	if (longestmatch == 0) {
+		return (0);
+	} else {
+		/*
+		 * Now we may have found the corresponding autofs mount
+		 * Try to find the matching global zone autofs entry
+		 */
+
+		for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
+			char p[MAXPATHLEN];
+			size_t zp_len;
+			size_t mp_len;
+
+			struct mnttab *mnt = mlp->mntl_mnt;
+
+			if (strcmp(mountmatch->mnt_special,
+			    mnt->mnt_special) != 0)
+				continue;
+			if (strcmp(mnt->mnt_fstype, MNTTYPE_AUTOFS))
+				continue;
+			if (strstr(mnt->mnt_mntopts, ZONE_OPT) != NULL)
+				continue;
+			/*
+			 * OK, we have a matching global zone automap
+			 * so adjust the path for the global zone.
+			 */
+			zp_len = strlen(zonepath);
+			mp_len = strlen(mnt->mnt_mountp);
+			(void) strncpy(p, globalpath + zp_len, MAXPATHLEN);
+			/*
+			 * If both global zone and zone-relative
+			 * mountpoint match, just use the same pathname
+			 */
+			if (strncmp(mnt->mnt_mountp, p, mp_len) == 0) {
+				(void) strncpy(globalpath, p, global_len);
+				return (1);
+			} else {
+				(void) strncpy(p, globalpath, MAXPATHLEN);
+				(void) strncpy(globalpath, mnt->mnt_mountp,
+				    global_len);
+				(void) strlcat(globalpath,
+				    p + strlen(mountmatch->mnt_mountp),
+				    global_len);
+				return (1);
+			}
+		}
+		return (0);
+	}
+}
+
+	/*
+	 * Find the pathname for the entry in mlist that corresponds to the
+	 * file named by path (i.e., that names a mount table entry for the
+	 * file system in which path lies).
+	 *
+	 * Return 0 is there an error.
+	 */
+	static int
+	getglobalpath(const char *path, zoneid_t zoneid, struct mntlist *mlist,
+	    char *globalpath)
+	{
+		struct mntlist *mlp;
+		char		lofspath[MAXPATHLEN];
+		char		zonepath[MAXPATHLEN];
+		int		longestmatch;
+		struct	mnttab	*mountmatch;
+
+		if (zoneid != GLOBAL_ZONEID) {
+			char	*prefix;
+
+			if ((prefix = getzonerootbyid(zoneid)) == NULL) {
+				return (0);
+			}
+			(void) strncpy(zonepath, prefix, MAXPATHLEN);
+			(void) strlcpy(globalpath, prefix, MAXPATHLEN);
+			(void) strlcat(globalpath, path, MAXPATHLEN);
+			free(prefix);
+		} else {
+			(void) strlcpy(globalpath, path, MAXPATHLEN);
+		}
+
+		for (;;) {
+			longestmatch = 0;
+			for (mlp = mlist; mlp; mlp = mlp->mntl_next) {
+				struct mnttab *mnt = mlp->mntl_mnt;
+				int	len;
+
+			if (subpath(globalpath, mnt->mnt_mountp) != 0)
+				continue;
+			len = strlen(mnt->mnt_mountp);
+			if (len > longestmatch) {
+				mountmatch = mnt;
+				longestmatch = len;
+			}
+		}
+		/*
+		 * Handle interesting mounts.
+		 */
+		if ((strcmp(mountmatch->mnt_fstype, MNTTYPE_NFS) == 0) ||
+		    (strcmp(mountmatch->mnt_fstype, MNTTYPE_AUTOFS) == 0)) {
+			if (zoneid > GLOBAL_ZONEID) {
+				struct mnttab *m = NULL;
+
+				if (strcmp(mountmatch->mnt_fstype,
+				    MNTTYPE_AUTOFS) == 0)
+					m = mountmatch;
+				if (getnfspathbyautofs(mlist, zoneid, m,
+				    globalpath, zonepath, MAXPATHLEN) == 0) {
+					return (0);
+				}
+			}
+			break;
+		} else if (strcmp(mountmatch->mnt_fstype, MNTTYPE_LOFS) == 0) {
+			/*
+			 * count up what's left
+			 */
+			int	remainder;
+
+			remainder = strlen(globalpath) - longestmatch;
+			if (remainder > 0) {
+				path = pathsuffix(globalpath,
+				    mountmatch->mnt_mountp);
+				(void) strlcpy(lofspath, path, MAXPATHLEN);
+			}
+			(void) strlcpy(globalpath, mountmatch->mnt_special,
+			    MAXPATHLEN);
+			if (remainder > 0) {
+				(void) strlcat(globalpath, lofspath,
+				    MAXPATHLEN);
+			}
+		} else {
+			if ((zoneid > GLOBAL_ZONEID) &&
+			    (strncmp(path, "/home/", strlen("/home/")) == 0)) {
+				char zonename[ZONENAME_MAX];
+
+				/*
+				 * If this is a cross-zone reference to
+				 * a home directory, it must be corrected.
+				 * We should only get here if the zone's
+				 * automounter hasn't yet mounted its
+				 * autofs trigger on /home.
+				 *
+				 * Since it is likely to do so in the
+				 * future, we will assume that the global
+				 * zone already has an equivalent autofs
+				 * mount established. By convention,
+				 * this should be mounted at the
+				 * /zone/<zonename>
+				 */
+
+				if (zone_getattr(zoneid, ZONE_ATTR_NAME,
+				    zonename, ZONENAME_MAX) == -1) {
+					return (0);
+				} else {
+					(void) snprintf(globalpath, MAXPATHLEN,
+					    "/zone/%s%s", zonename, path);
+				}
+			}
+			break;
+		}
+	}
+	return (1);
+}
+
+
+/*
+ * This function is only useful for global zone callers
+ * It uses the global zone mnttab to translate local zone pathnames
+ * into global zone pathnames.
+ */
+char *
+getpathbylabel(const char *path_name, char *resolved_path, size_t bufsize,
+    const bslabel_t *sl) {
+	char		ret_path[MAXPATHLEN];	/* pathname to return */
+	zoneid_t	zoneid;
+	struct mntlist *mlist;
+
+	if (getzoneid() != GLOBAL_ZONEID) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (path_name[0] != '/') {		/* need absolute pathname */
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (resolved_path == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((zoneid = getzoneidbylabel(sl)) == -1)
+		return (NULL);
+
+	/*
+	 * Construct the list of mounted file systems.
+	 */
+
+	if ((mlist = tsol_mkmntlist()) == NULL) {
+		return (NULL);
+	}
+	if (getglobalpath(path_name, zoneid, mlist, ret_path) == 0) {
+		tsol_mlist_free(mlist);
+		return (NULL);
+	}
+	tsol_mlist_free(mlist);
+	if (strlen(ret_path) >= bufsize) {
+		errno = EFAULT;
+		return (NULL);
+	}
+	return (strcpy(resolved_path, ret_path));
+} /* end getpathbylabel() */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/getplabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include	<stdlib.h>
+#include	<zone.h>
+#include 	<tsol/label.h>
+#include 	<sys/tsol/label_macro.h>
+#include	<sys/types.h>
+#include	<sys/zone.h>
+
+/*
+ * getplabel(2TSOL) - get process sensitivity label
+ */
+
+int
+getplabel(bslabel_t *label_p)
+{
+	zoneid_t zoneid;
+
+	zoneid = (int)getzoneid();
+	if (zoneid == GLOBAL_ZONEID) {
+		bslhigh(label_p);
+	} else {
+		bslabel_t *sl;
+
+		sl = getzonelabelbyid(zoneid);
+		if (sl == NULL) {
+			return (-1);
+		} else {
+			*label_p = *sl;
+			free(sl);
+		}
+	}
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/hextob.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,97 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *      hextob.c - Hexadecimal string to binary label conversion.
+ *
+ *              These routines convert canonical hexadecimal representations
+ *	of internal labels into binary form.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
+/*
+ *	htobsl - Convert a Hexadecimal label string to a Sensitivity Label.
+ *
+ *	Entry	s = Hexadecimal label string to be converted.
+ *
+ *	Exit	label = Sensitivity Label converted, if successful.
+ *			Unchanged, if not successful.
+ *
+ *	Returns	1, If successful.
+ *		0, Otherwise.
+ *
+ *	Calls	str_to_label, m_label_free.
+ */
+
+int
+htobsl(const char *s, m_label_t *label)
+{
+	m_label_t *l = NULL;
+
+	if (str_to_label(s, &l, MAC_LABEL, L_NO_CORRECTION, NULL) == -1) {
+		m_label_free(l);
+		return (0);
+	}
+	*label = *l;
+	m_label_free(l);
+	return (1);
+}
+
+/*
+ *	htobclear - Convert a Hexadecimal label string to a Clearance.
+ *
+ *	Entry	s = Hexadecimal label string to be converted.
+ *
+ *	Exit	clearance = Clearnace converted, if successful.
+ *			    Unchanged, if not successful.
+ *
+ *	Returns	1, If successful.
+ *		0, Otherwise.
+ *
+ *	Calls	str_to_label, m_label_free.
+ */
+
+int
+htobclear(const char *s, m_label_t *clearance)
+{
+	m_label_t *c = NULL;
+
+	if (str_to_label(s, &c, USER_CLEAR, L_NO_CORRECTION, NULL) == -1) {
+		m_label_free(c);
+		return (0);
+	}
+	*clearance = *c;
+	m_label_free(c);
+	return (1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/label.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,242 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_TSOL_LABEL_H
+#define	_TSOL_LABEL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/tsol/label.h>
+#include <priv.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Procedural Interface Structure Definitions */
+
+struct	label_info {		/* structure returned by label_info */
+	short	ilabel_len;		/* max Information Label length */
+	short	slabel_len;		/* max Sensitivity Label length */
+	short	clabel_len;		/* max CMW Label length */
+	short	clear_len;		/* max Clearance Label length */
+	short	vers_len;		/* version string length */
+	short	header_len;		/* max len of banner page header */
+	short	protect_as_len;		/* max len of banner page protect as */
+	short	caveats_len;		/* max len of banner page caveats */
+	short	channels_len;		/* max len of banner page channels */
+};
+
+typedef struct label_set_identifier {	/* valid label set identifier */
+	int	type;			/* type of the set */
+	char	*name;			/* name of the set if needed */
+} set_id;
+
+struct name_fields {		/* names for label builder fields */
+	char	*class_name;		/* Classifications field name */
+	char	*comps_name;		/* Compartments field name */
+	char	*marks_name;		/* Markings field name */
+};
+
+/* Label Set Identifier Types */
+
+/*
+ * The accreditation ranges as specified in the label encodings file.
+ * The name parameter is ignored.
+ *
+ * System Accreditation Range is all valid labels plus Admin High and Low.
+ *
+ * User Accreditation Range is valid user labels as defined in the
+ *	ACCREDITATION RANGE: section of the label encodings file.
+ */
+
+#define	SYSTEM_ACCREDITATION_RANGE	1
+#define	USER_ACCREDITATION_RANGE	2
+
+
+/* System Call Interface Definitions */
+
+extern int getlabel(const char *, m_label_t *);
+extern int fgetlabel(int, m_label_t *);
+
+extern int getplabel(m_label_t *);
+extern int setflabel(const char *, m_label_t *);
+extern char *getpathbylabel(const char *, char *, size_t,
+    const m_label_t *sl);
+extern m_label_t *getzonelabelbyid(zoneid_t);
+extern m_label_t *getzonelabelbyname(const char *);
+extern zoneid_t getzoneidbylabel(const m_label_t *);
+extern char *getzonenamebylabel(const m_label_t *);
+extern char *getzonerootbyid(zoneid_t);
+extern char *getzonerootbyname(const char *);
+extern char *getzonerootbylabel(const m_label_t *);
+extern m_label_t *getlabelbypath(const char *);
+
+
+/* Flag word values */
+
+#define	ALL_ENTRIES		0x00000000
+#define	ACCESS_RELATED		0x00000001
+#define	ACCESS_MASK		0x0000FFFF
+#define	ACCESS_SHIFT		0
+
+#define	LONG_WORDS		0x00010000	/* use long names */
+#define	SHORT_WORDS		0x00020000	/* use short names if present */
+#define	LONG_CLASSIFICATION	0x00040000	/* use long classification */
+#define	SHORT_CLASSIFICATION	0x00080000	/* use short classification */
+#define	NO_CLASSIFICATION	0x00100000	/* don't translate the class */
+#define	VIEW_INTERNAL		0x00200000	/* don't promote/demote */
+#define	VIEW_EXTERNAL		0x00400000	/* promote/demote label */
+
+#define	NEW_LABEL		0x00000001	/* create a full new label */
+#define	NO_CORRECTION		0x00000002	/* don't correct label errors */
+						/* implies NEW_LABEL */
+
+#define	CVT_DIM			0x01		/* display word dimmed */
+#define	CVT_SET			0x02		/* display word currently set */
+
+/* Procedure Interface Definitions available to user */
+
+/* APIs shared with the kernel are in <sys/tsol/label.h */
+
+extern m_label_t *blabel_alloc(void);
+extern void	blabel_free(m_label_t *);
+extern size_t   blabel_size(void);
+extern char	*bsltoh(const m_label_t *);
+extern char	*bcleartoh(const m_label_t *);
+
+extern char	*bsltoh_r(const m_label_t *, char *);
+extern char	*bcleartoh_r(const m_label_t *, char *);
+extern char	*h_alloc(uint8_t);
+extern void	h_free(char *);
+
+extern int	htobsl(const char *, m_label_t *);
+extern int	htobclear(const char *, m_label_t *);
+
+extern m_range_t	*getuserrange(const char *);
+extern m_range_t	*getdevicerange(const char *);
+
+extern int	set_effective_priv(priv_op_t, int, ...);
+extern int	set_inheritable_priv(priv_op_t, int, ...);
+extern int	set_permitted_priv(priv_op_t, int, ...);
+extern int	is_system_labeled(void);
+
+/* Procedures needed for multi-level printing */
+
+extern int	tsol_check_admin_auth(uid_t uid);
+
+/* APIs implemented via labeld */
+
+extern int	blinset(const m_label_t *, const set_id *);
+extern int	labelinfo(struct label_info *);
+extern ssize_t	labelvers(char **, size_t);
+extern char	*bltocolor(const m_label_t *);
+extern char	*bltocolor_r(const m_label_t *, size_t, char *);
+
+extern ssize_t	bsltos(const m_label_t *, char **, size_t, int);
+extern ssize_t	bcleartos(const m_label_t *, char **, size_t, int);
+
+
+extern char	*sbsltos(const m_label_t *, size_t);
+extern char	*sbcleartos(const m_label_t *, size_t);
+
+
+extern int	stobsl(const char *, m_label_t *, int, int *);
+extern int	stobclear(const char *, m_label_t *, int, int *);
+extern int	bslvalid(const m_label_t *);
+extern int	bclearvalid(const m_label_t *);
+
+/* Manifest human readable label names */
+
+#define	ADMIN_LOW	"ADMIN_LOW"
+#define	ADMIN_HIGH	"ADMIN_HIGH"
+
+/* DIA label conversion and parsing */
+
+/* Conversion types */
+
+typedef	enum _m_label_str {
+	M_LABEL = 1,		/* process or user clearance */
+	M_INTERNAL = 2,		/* internal form for use in public databases */
+	M_COLOR = 3,		/* process label color */
+	PRINTER_TOP_BOTTOM = 4,	/* DIA banner page top/bottom */
+	PRINTER_LABEL = 5,	/* DIA banner page label */
+	PRINTER_CAVEATS = 6,	/* DIA banner page caveats */
+	PRINTER_CHANNELS = 7	/* DIA banner page handling channels */
+} m_label_str_t;
+
+/* Flags for conversion, not all flags apply to all types */
+#define	DEF_NAMES	0x1
+#define	SHORT_NAMES	0x3	/* short names are prefered where defined */
+#define	LONG_NAMES	0x4	/* long names are prefered where defined */
+
+extern int label_to_str(const m_label_t *, char **, const m_label_str_t,
+    uint_t);
+
+/* Parsing types */
+typedef enum _m_label_type {
+	MAC_LABEL = 1,		/* process or object label */
+	USER_CLEAR = 2		/* user's clearance (LUB) */
+} m_label_type_t;
+
+/* Flags for parsing */
+
+#define	L_DEFAULT		0x0
+#define	L_MODIFY_EXISTING	0x1	/* start parsing with existing label */
+#define	L_NO_CORRECTION		0x2	/* must be correct by l_e rules */
+
+/* EINVAL sub codes */
+
+#define	M_BAD_STRING		-3	/* DIA L_BAD_LABEL */
+	/* bad requested label type, bad previous label type */
+#define	M_BAD_LABEL		-2	/* DIA L_BAD_CLASSIFICATION, */
+
+extern int str_to_label(const char *, m_label_t **, const m_label_type_t,
+    uint_t, int *);
+
+extern m_label_t *m_label_alloc(const m_label_type_t);
+
+extern int m_label_dup(m_label_t **, const m_label_t *);
+
+extern void m_label_free(m_label_t *);
+
+/* Contract Private interfaces with the label builder GUIs */
+
+extern int	bslcvtfull(const m_label_t *, const m_range_t *, int,
+    char **, char **[], char **[], char *[], int *, int *);
+extern int	bslcvt(const m_label_t *, int, char **, char *[]);
+extern int	bclearcvtfull(const m_label_t *, const m_range_t *, int,
+    char **, char **[], char **[], char *[], int *, int *);
+extern int	bclearcvt(const m_label_t *, int, char **, char *[]);
+
+extern int	labelfields(struct name_fields *);
+extern int	userdefs(m_label_t *, m_label_t *);
+extern int	zonecopy(m_label_t *, char *, char *, char *, int);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* !_TSOL_LABEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/labeld.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,473 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_LABELD_H
+#define	_LABELD_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ *	Definitions for the call parameters for the door-based label
+ * translation service.
+ */
+
+#define	BUFSIZE	4096
+
+#define	DOOR_PATH	"/var/tsol/doors/"
+#define	DOOR_NAME	"labeld"
+#define	COOKIE		(void *)0x6c616264	/* "labd" */
+
+/*	Op codes */
+
+/*	Labeld Commands */
+
+#define	LABELDNULL	1
+
+/*	Miscellaneous */
+
+#define	BLINSET		10
+#define	BSLVALID	11
+#define	BILVALID	12
+#define	BCLEARVALID	13
+#define	LABELINFO	14
+#define	LABELVERS	15
+#define	BLTOCOLOR	16
+
+/*	Binary to String Label Translation */
+
+#define	BSLTOS		23
+#define	BCLEARTOS	25
+
+/*	String to Binary Label Translation */
+
+#define	STOBSL		31
+#define	STOBCLEAR	33
+
+/*
+ *	Dimming List Routines
+ *	Contract private for label builders
+ */
+
+#define	BSLCVT		40
+#define	BCLEARCVT	42
+#define	LABELFIELDS	43
+#define	UDEFS		44
+
+#define	GETFLABEL	45
+#define	SETFLABEL	46
+#define	ZCOPY		47
+
+/* NEW LABELS */
+/* DIA printer banner labels */
+
+#define	PR_CAVEATS	101
+#define	PR_CHANNELS	102
+#define	PR_LABEL	103
+#define	PR_TOP		104
+
+/* DIA label to string  */
+
+#define	LTOS		105
+
+/* DIA string to label */
+
+#define	STOL		106
+
+/*	Structures */
+
+typedef	uint_t	bufp_t;		/* offset into buf[] in/out string buffer */
+
+/* Null call */
+
+typedef	struct {
+	int	null;
+} null_call_t;
+
+typedef	struct {
+	int	null;
+} null_ret_t;
+
+/* Miscellaneous interfaces */
+
+typedef	struct {
+	bslabel_t label;
+	int	type;
+} inset_call_t;
+
+typedef	struct {
+	int	inset;
+} inset_ret_t;
+
+typedef	struct {
+	bslabel_t label;
+} slvalid_call_t;
+
+typedef	struct {
+	int	valid;
+} slvalid_ret_t;
+
+typedef	struct {
+	bclear_t clear;
+} clrvalid_call_t;
+
+typedef	struct {
+	int	valid;
+} clrvalid_ret_t;
+
+typedef	struct {
+	int	null;
+} info_call_t;
+
+typedef	struct {
+	struct label_info info;
+} info_ret_t;
+
+typedef	struct {
+	int	null;
+} vers_call_t;
+
+typedef	struct {
+	char	vers[BUFSIZE];
+} vers_ret_t;
+
+typedef struct {
+	blevel_t label;
+} color_call_t;
+
+typedef struct {
+	char	color[BUFSIZE];
+} color_ret_t;
+
+/* Binary Label to String interfaces */
+
+typedef	struct {
+	bslabel_t label;
+	uint_t	flags;
+} bsltos_call_t;
+
+typedef	struct {
+	char	slabel[BUFSIZE];
+} bsltos_ret_t;
+
+typedef	struct {
+	bclear_t clear;
+	uint_t	flags;
+} bcleartos_call_t;
+
+typedef	struct {
+	char	cslabel[BUFSIZE];
+} bcleartos_ret_t;
+
+/* String to Binary Label interfaces */
+
+typedef	struct {
+	bslabel_t label;
+	uint_t	flags;
+	char	string[BUFSIZE];
+} stobsl_call_t;
+
+typedef	struct {
+	bslabel_t label;
+} stobsl_ret_t;
+
+typedef	struct {
+	bclear_t clear;
+	uint_t	flags;
+	char	string[BUFSIZE];
+} stobclear_call_t;
+
+typedef	struct {
+	bclear_t clear;
+} stobclear_ret_t;
+
+/*
+ * The following Dimming List and Miscellaneous interfaces
+ * implement contract private interfaces for the label builder
+ * interfaces.
+ */
+
+/* Dimming List interfaces */
+
+typedef	struct {
+	bslabel_t label;
+	brange_t bounds;
+	uint_t	flags;
+} bslcvt_call_t;
+
+typedef	struct {
+	bufp_t	string;
+	bufp_t	dim;
+	bufp_t	lwords;
+	bufp_t	swords;
+	size_t	d_len;
+	size_t	l_len;
+	size_t	s_len;
+	int	first_comp;
+	int	first_mark;
+	char	buf[BUFSIZE];
+} cvt_ret_t;
+
+typedef cvt_ret_t bslcvt_ret_t;
+
+typedef	struct {
+	bclear_t clear;
+	brange_t bounds;
+	uint_t	flags;
+} bclearcvt_call_t;
+
+typedef cvt_ret_t bclearcvt_ret_t;
+
+/* Miscellaneous interfaces */
+
+typedef	struct {
+	int	null;
+} fields_call_t;
+
+typedef	struct {
+	bufp_t	classi;
+	bufp_t	compsi;
+	bufp_t	marksi;
+	char	buf[BUFSIZE];
+} fields_ret_t;
+
+typedef	struct {
+	int	null;
+} udefs_call_t;
+
+typedef	struct {
+	bslabel_t sl;
+	bclear_t  clear;
+} udefs_ret_t;
+
+typedef	struct {
+	bslabel_t  sl;
+	char	pathname[BUFSIZE];
+} setfbcl_call_t;
+
+typedef	struct {
+	int	status;
+} setfbcl_ret_t;
+
+typedef	struct {
+	bslabel_t  src_win_sl;
+	int	transfer_mode;
+	bufp_t  remote_dir;
+	bufp_t  filename;
+	bufp_t  local_dir;
+	bufp_t  display;
+	char    buf[BUFSIZE];
+} zcopy_call_t;
+
+typedef	struct {
+	int	status;
+} zcopy_ret_t;
+
+typedef	struct {
+	m_label_t label;
+	uint_t	flags;
+} pr_call_t;
+
+typedef	struct {
+	char	buf[BUFSIZE];
+} pr_ret_t;
+
+typedef	struct {
+	m_label_t label;
+	uint_t	flags;
+} ls_call_t;
+
+typedef	struct {
+	char	buf[BUFSIZE];
+} ls_ret_t;
+
+typedef	struct {
+	m_label_t label;
+	uint_t	flags;
+	char	string[BUFSIZE];
+} sl_call_t;
+
+typedef	struct {
+	m_label_t label;
+} sl_ret_t;
+
+/* Labeld operation call structure */
+
+typedef	struct {
+	uint_t	op;
+	union	{
+		null_call_t	null_arg;
+
+		inset_call_t	inset_arg;
+		slvalid_call_t	slvalid_arg;
+		clrvalid_call_t	clrvalid_arg;
+		info_call_t	info_arg;
+		vers_call_t	vers_arg;
+		color_call_t	color_arg;
+
+		bsltos_call_t	bsltos_arg;
+		bcleartos_call_t	bcleartos_arg;
+
+		stobsl_call_t	stobsl_arg;
+		stobclear_call_t	stobclear_arg;
+
+		bslcvt_call_t	bslcvt_arg;
+		bclearcvt_call_t	bclearcvt_arg;
+		fields_call_t	fields_arg;
+		udefs_call_t	udefs_arg;
+		setfbcl_call_t	setfbcl_arg;
+		zcopy_call_t	zcopy_arg;
+		pr_call_t	pr_arg;
+		ls_call_t	ls_arg;
+		sl_call_t	sl_arg;
+	} cargs;
+} labeld_call_t;
+
+/* Labeld operation return structure */
+
+typedef struct {
+	int	ret;		/* labeld return codes */
+	int	err;		/* function error codes */
+	union	{
+		null_ret_t	null_ret;
+
+		inset_ret_t	inset_ret;
+		slvalid_ret_t	slvalid_ret;
+		clrvalid_ret_t	clrvalid_ret;
+		info_ret_t	info_ret;
+		vers_ret_t	vers_ret;
+		color_ret_t	color_ret;
+
+		bsltos_ret_t	bsltos_ret;
+		bcleartos_ret_t	bcleartos_ret;
+
+		stobsl_ret_t	stobsl_ret;
+		stobclear_ret_t	stobclear_ret;
+
+		bslcvt_ret_t	bslcvt_ret;
+		bclearcvt_ret_t	bclearcvt_ret;
+		fields_ret_t	fields_ret;
+		udefs_ret_t	udefs_ret;
+		setfbcl_ret_t	setfbcl_ret;
+		zcopy_ret_t	zcopy_ret;
+		pr_ret_t	pr_ret;
+		ls_ret_t	ls_ret;
+		sl_ret_t	sl_ret;
+	} rvals;
+} labeld_ret_t;
+
+/* Labeld call/return structure */
+
+typedef	struct {
+	union {
+		labeld_call_t	acall;
+		labeld_ret_t	aret;
+	} param;
+} labeld_data_t;
+
+#define	callop	param.acall.op
+#define	retret	param.aret.ret
+#define	reterr	param.aret.err
+
+#define	CALL_SIZE(type, buf)	(size_t)(sizeof (type) + sizeof (int) + (buf))
+#define	RET_SIZE(type, buf)	(size_t)(sizeof (type) + 2*sizeof (int) + (buf))
+
+/* Labeld common client call function */
+
+int
+__call_labeld(labeld_data_t **dptr, size_t *ndata, size_t *adata);
+
+/* Return Codes */
+
+#define	SUCCESS		1	/* Call OK */
+#define	NOTFOUND	-1	/* Function not found */
+#define	SERVERFAULT	-2	/* Internal labeld error */
+#define	NOSERVER	-3	/* No server thread available, try later */
+
+/* Flag Translation Values */
+
+#define	L_NEW_LABEL		0x10000000
+
+/* GFI FLAGS */
+
+#define	GFI_FLAG_MASK		 0x0000FFFF
+#define	GFI_ACCESS_RELATED	 0x00000001
+
+/* binary to ASCII */
+
+#define	LABELS_NO_CLASS		 0x00010000
+#define	LABELS_SHORT_CLASS	 0x00020000
+#define	LABELS_SHORT_WORDS	 0x00040000
+
+/* Label view */
+
+#define	LABELS_VIEW_INTERNAL	 0x00100000
+#define	LABELS_VIEW_EXTERNAL	 0x00200000
+
+/* Dimming list (convert -- b*cvt* ) */
+
+#define	LABELS_FULL_CONVERT	 0x00010000
+
+/* ASCII to binary */
+
+#define	LABELS_NEW_LABEL	 0x00010000
+#define	LABELS_FULL_PARSE	 0x00020000
+#define	LABELS_ONLY_INFO_LABEL	 0x00040000
+
+#define	MOVE_FILE	0
+#define	COPY_FILE	1
+#define	LINK_FILE	2
+
+#define	PIPEMSG_FILEOP_ERROR	1
+#define	PIPEMSG_EXIST_ERROR	2
+#define	PIPEMSG_DONE 		7
+#define	PIPEMSG_PATH_ERROR	20
+#define	PIPEMSG_ZONE_ERROR	21
+#define	PIPEMSG_LABEL_ERROR	22
+#define	PIPEMSG_READ_ERROR	23
+#define	PIPEMSG_READONLY_ERROR  24
+#define	PIPEMSG_WRITE_ERROR	25
+#define	PIPEMSG_CREATE_ERROR	26
+#define	PIPEMSG_DELETE_ERROR	27
+#define	PIPEMSG_CANCEL		101
+#define	PIPEMSG_PROCEED		102
+#define	PIPEMSG_MERGE		103
+#define	PIPEMSG_REPLACE_BUFFER	104
+#define	PIPEMSG_RENAME_BUFFER	105
+#define	PIPEMSG_MULTI_PROCEED	106
+#define	PIPEMSG_RENAME_FILE	107
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LABELD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/llib-ltsol	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,35 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <tsol/label.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/priv.h>
+#include <sys/tsol/label_macro.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/ltos.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,283 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/tsol/label_macro.h>
+
+#include <tsol/label.h>
+
+#include "clnt.h"
+#include "labeld.h"
+
+static _mac_label_impl_t low;
+static _mac_label_impl_t high;
+static int	inited = 0;
+
+/* 0x + Classification + '-' + ll + '-' + Compartments + end of string */
+#define	_HEX_SIZE 2+(sizeof (Classification_t)*2)+4+\
+	(sizeof (Compartments_t)*2)+1
+
+/* 0x + Classification + '-' + ll + '-' + end of string */
+#define	_MIN_HEX (2 + (sizeof (Classification_t)*2) + 4 + 1)
+
+static char digits[] = "0123456789abcdef";
+
+#define	HEX(h, i, l, s) \
+	for (; i < s; /* */) {\
+	h[i++] = digits[(unsigned int)(*l >> 4)];\
+	h[i++] = digits[(unsigned int)(*l++&0xF)]; }
+
+static int
+__hex(char **s, const m_label_t *l)
+{
+	char	*hex;
+	int	i = 0;
+	uchar_t *hl;
+	int	hex_len;
+	uchar_t *len;
+
+	hl = (uchar_t  *)&(((_mac_label_impl_t *)l)->_c_len);
+	len = hl;
+
+	if (*len == 0) {
+		/* old binary label */
+		hex_len = _HEX_SIZE;
+	} else {
+		hex_len = _MIN_HEX + (*len * sizeof (uint32_t) * 2);
+	}
+
+	if ((hex = malloc(hex_len)) == NULL) {
+		return (-1);
+	}
+
+	/* header */
+
+	hex[i++] = '0';
+	hex[i++] = 'x';
+
+	/* classification */
+
+	hl++;		/* start at classification */
+	HEX(hex, i, hl, 6);
+
+	/* Add compartments length */
+	hex[i++] = '-';
+	HEX(hex, i, len, 9);
+	hex[i++] = '-';
+
+	/* compartments */
+	HEX(hex, i, hl, hex_len-1);
+	hex[i] = '\0';
+
+	/* truncate trailing zeros */
+
+	while (hex[i-1] == '0' && hex[i-2] == '0') {
+		i -= 2;
+	}
+	hex[i] = '\0';
+
+	if ((*s = strdup(hex)) == NULL) {
+		free(hex);
+		return (-1);
+	}
+
+	free(hex);
+	return (0);
+
+}
+
+/*
+ * label_to_str -- convert a label to the requested type of string.
+ *
+ *	Entry	l = label to convert;
+ *		t = type of conversion;
+ *		f = flags for conversion type;
+ *
+ *	Exit	*s = allocated converted string;
+ *		     Caller must call free() to free.
+ *
+ *	Returns	0, success.
+ *		-1, error, errno set; *s = NULL.
+ *
+ *	Calls	labeld
+ */
+
+int
+label_to_str(const m_label_t *l, char **s, const m_label_str_t t, uint_t f)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize;
+	int	err;
+
+	if (inited == 0) {
+		inited = 1;
+		_BSLLOW(&low);
+		_BSLHIGH(&high);
+	}
+
+#define	lscall callp->param.acall.cargs.ls_arg
+#define	lsret callp->param.aret.rvals.ls_ret
+	switch (t) {
+	case M_LABEL:
+		call.callop = LTOS;
+		lscall.label = *l;
+		lscall.flags = f;
+		datasize = CALL_SIZE(ls_call_t, 0);
+		if ((err = __call_labeld(&callp, &bufsize, &datasize)) ==
+		    SUCCESS) {
+			if (callp->reterr != 0) {
+				errno = EINVAL;
+				*s = NULL;
+				return (-1);
+			}
+			if ((*s = strdup(lsret.buf)) == NULL) {
+				return (-1);
+			}
+			if (callp != &call) {
+				/* release returned buffer */
+				(void) munmap((void *)callp, bufsize);
+			}
+			return (0);
+		}
+		switch (err) {
+		case NOSERVER:
+			/* server not present */
+			/* special case admin_low and admin_high */
+
+			if (_MEQUAL(&low, (_mac_label_impl_t *)l)) {
+				if ((*s = strdup(ADMIN_LOW)) == NULL) {
+					return (-1);
+				}
+				return (0);
+			} else if (_MEQUAL(&high, (_mac_label_impl_t *)l)) {
+				if ((*s = strdup(ADMIN_HIGH)) == NULL) {
+					return (-1);
+				}
+				return (0);
+			}
+			errno = ENOTSUP;
+			break;
+		default:
+			errno = EINVAL;
+			break;
+		}
+		*s = NULL;
+		return (-1);
+#undef	lscall
+#undef	lsret
+
+	case M_INTERNAL: {
+		if (!(_MTYPE(l, SUN_MAC_ID) ||
+		    _MTYPE(l, SUN_UCLR_ID))) {
+			errno = EINVAL;
+			return (-1);
+		}
+		if (_MEQUAL(&low, (_mac_label_impl_t *)l)) {
+			if ((*s = strdup(ADMIN_LOW)) == NULL) {
+				return (-1);
+			}
+			return (0);
+		}
+		if (_MEQUAL(&high, (_mac_label_impl_t *)l)) {
+			if ((*s = strdup(ADMIN_HIGH)) == NULL) {
+				return (-1);
+			}
+			return (0);
+		}
+
+		return (__hex(s, l));
+	}
+
+#define	ccall callp->param.acall.cargs.color_arg
+#define	cret callp->param.aret.rvals.color_ret
+	case M_COLOR:
+		datasize = CALL_SIZE(color_call_t, 0);
+		call.callop = BLTOCOLOR;
+		ccall.label = *l;
+
+		if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+			errno = ENOTSUP;
+			*s = NULL;
+			return (-1);
+		} if (callp->reterr != 0) {
+			errno = EINVAL;
+			*s = NULL;
+			return (-1);
+		}
+		if ((*s = strdup(cret.color)) == NULL) {
+			return (-1);
+		}
+		return (0);
+#undef	ccall
+#undef	cret
+
+#define	prcall	callp->param.acall.cargs.pr_arg
+#define	prret	callp->param.aret.rvals.pr_ret
+	case PRINTER_TOP_BOTTOM:
+		call.callop = PR_TOP;
+		break;
+	case PRINTER_LABEL:
+		call.callop = PR_LABEL;
+		break;
+	case PRINTER_CAVEATS:
+		call.callop = PR_CAVEATS;
+		break;
+	case PRINTER_CHANNELS:
+		call.callop = PR_CHANNELS;
+		break;
+	default:
+		errno = EINVAL;
+		*s = NULL;
+		return (-1);
+	}
+	/* do the common printer calls */
+	datasize = CALL_SIZE(pr_call_t, 0);
+	prcall.label = *l;
+	prcall.flags = f;
+	if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+		errno = ENOTSUP;
+		*s = NULL;
+		return (-1);
+	} if (callp->reterr != 0) {
+		errno = EINVAL;
+		*s = NULL;
+		return (-1);
+	}
+	if ((*s = strdup(prret.buf)) == NULL) {
+		return (-1);
+	}
+	return (0);
+#undef	prcall
+#undef	prret
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/misc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,476 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+
+/*
+ *	Miscellaneous user interfaces to trusted label functions.
+ *
+ */
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <sys/mman.h>
+
+#include <tsol/label.h>
+
+#include "labeld.h"
+#include "clnt.h"
+#include <sys/tsol/label_macro.h>
+#include <secdb.h>
+#include <user_attr.h>
+
+static	bslabel_t slow, shigh;	/* static Admin Low and High SLs */
+static	bclear_t  clow, chigh;	/* static Admin Low and High CLRs */
+
+static char color[MAXCOLOR];
+
+
+#define	incall callp->param.acall.cargs.inset_arg
+#define	inret callp->param.aret.rvals.inset_ret
+/*
+ *	blinset - Check in a label set.
+ *
+ *	Entry	label = Sensitivity Label to check.
+ *		id    = Label set identifier of set to check.
+ *
+ *	Exit	None.
+ *
+ *	Returns	-1, If label set unavailable, or server failure.
+ *		 0, If label not in label set.
+ *		 1, If label is in the label set.
+ *
+ *	Calls	__call_labeld(BLINSET), BLTYPE, BSLLOW, BSLHIGH.
+ *
+ *	Uses	slow, shigh.
+ */
+
+int
+blinset(const bslabel_t *label, const set_id *id)
+{
+	if (id->type == SYSTEM_ACCREDITATION_RANGE) {
+		if (!BLTYPE(&slow, SUN_SL_ID)) {
+			/* initialize static labels. */
+
+			BSLLOW(&slow);
+			BSLHIGH(&shigh);
+		}
+
+		if (BLTYPE(label, SUN_SL_ID) &&
+		    (BLEQUAL(label, &slow) || BLEQUAL(label, &shigh)))
+
+			return (1);
+	}
+	if (id->type == USER_ACCREDITATION_RANGE ||
+	    id->type == SYSTEM_ACCREDITATION_RANGE) {
+		labeld_data_t	call;
+		labeld_data_t	*callp = &call;
+		size_t	bufsize = sizeof (labeld_data_t);
+		size_t	datasize = CALL_SIZE(inset_call_t, 0);
+
+		call.callop = BLINSET;
+		incall.label = *label;
+		incall.type = id->type;
+
+		if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+			/* process error */
+
+			return (-1);
+		}
+		return (inret.inset);
+	} else {
+		/*
+		 * Only System and User Accreditation Ranges presently
+		 * implemented.
+		 */
+		return (-1);
+	}
+}
+#undef	incall
+#undef	inret
+
+#define	slvcall callp->param.acall.cargs.slvalid_arg
+#define	slvret callp->param.aret.rvals.slvalid_ret
+/*
+ *	bslvalid - Check Sensitivity Label for validity.
+ *
+ *	Entry	label = Sensitivity Label to check.
+ *
+ *	Exit	None.
+ *
+ *	Returns	-1, If unable to access label encodings file, or server failure.
+ *		 0, If label not valid.
+ *		 1, If label is valid.
+ *
+ *	Calls	__call_labeld(BSLVALID), BLTYPE, BSLLOW, BSLHIGH.
+ *
+ *	Uses	slow, shigh.
+ *
+ */
+
+int
+bslvalid(const bslabel_t *label)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(slvalid_call_t, 0);
+
+	if (!BLTYPE(&slow, SUN_SL_ID)) {
+		/* initialize static labels. */
+
+		BSLLOW(&slow);
+		BSLHIGH(&shigh);
+	}
+
+	if (BLTYPE(label, SUN_SL_ID) &&
+	    (BLEQUAL(label, &slow) || BLEQUAL(label, &shigh))) {
+
+		return (1);
+	}
+
+	call.callop = BSLVALID;
+	slvcall.label = *label;
+
+	if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+		/* process error */
+
+		return (-1);
+	}
+	return (slvret.valid);
+}
+#undef	slvcall
+#undef	slvret
+
+#define	clrvcall callp->param.acall.cargs.clrvalid_arg
+#define	clrvret callp->param.aret.rvals.clrvalid_ret
+/*
+ *	bclearvalid - Check Clearance for validity.
+ *
+ *	Entry	clearance = Clearance to check.
+ *
+ *	Exit	None.
+ *
+ *	Returns	-1, If unable to access label encodings file, or server failure.
+ *		 0, If label not valid.
+ *		 1, If label is valid.
+ *
+ *	Calls	__call_labeld(BCLEARVALID), BLTYPE, BCLEARLOW, BCLEARHIGH.
+ *
+ *	Uses	clow, chigh.
+ *
+ */
+
+int
+bclearvalid(const bclear_t *clearance)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(clrvalid_call_t, 0);
+
+	if (!BLTYPE(&clow, SUN_CLR_ID)) {
+		/* initialize static labels. */
+
+		BCLEARLOW(&clow);
+		BCLEARHIGH(&chigh);
+	}
+
+	if (BLTYPE(clearance, SUN_CLR_ID) &&
+	    (BLEQUAL(clearance, &clow) || BLEQUAL(clearance, &chigh))) {
+
+		return (1);
+	}
+
+	call.callop = BCLEARVALID;
+	clrvcall.clear = *clearance;
+
+	if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+		/* process error */
+
+		return (-1);
+	}
+	return (clrvret.valid);
+}
+#undef	clrvcall
+#undef	clrvret
+
+#define	inforet callp->param.aret.rvals.info_ret
+/*
+ *	labelinfo - Get information about the label encodings file.
+ *
+ *	Entry	info = Address of label_info structure to update.
+ *
+ *	Exit	info = Updated.
+ *
+ *	Returns	-1, If unable to access label encodings file, or server failure.
+ *		 1, If successful.
+ *
+ *	Calls	__call_labeld(LABELINFO).
+ */
+
+int
+labelinfo(struct label_info *info)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(info_call_t, 0);
+	int	rval;
+
+	call.callop = LABELINFO;
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) != SUCCESS) {
+		/* process error */
+
+		return (-1);
+	}
+	*info = inforet.info;
+	return (rval);
+}
+#undef	inforet
+
+#define	lvret callp->param.aret.rvals.vers_ret
+/*
+ *	labelvers - Get version string of the label encodings file.
+ *
+ *	Entry	version = Address of string pointer to return.
+ *		len = Length of string if pre-allocated.
+ *
+ *	Exit	version = Updated.
+ *
+ *	Returns	-1, If unable to access label encodings file, or server failure.
+ *		 0, If unable to allocate version string,
+ *			or pre-allocated version string to short
+ *			(and **version = '\0').
+ *		length (including null) of version string, If successful.
+ *
+ *	Calls	__call_labeld(LABELVERS)
+ *			malloc, strlen.
+ */
+
+ssize_t
+labelvers(char **version, size_t len)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(vers_call_t, 0);
+	size_t	ver_len;
+
+	call.callop = LABELVERS;
+
+	if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
+
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (-1);
+	}
+
+	/* unpack length */
+
+	ver_len = strlen(lvret.vers) + 1;
+	if (*version == NULL) {
+		if ((*version = malloc(ver_len)) == NULL) {
+			if (callp != &call)
+				/* release return buffer */
+				(void) munmap((void *)callp, bufsize);
+			return (0);
+		}
+	} else if (ver_len > len) {
+		**version = '\0';
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+	(void) strcpy(*version, lvret.vers);
+
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (ver_len);
+}  /* labelvers */
+#undef	lvret
+
+#define	ccall callp->param.acall.cargs.color_arg
+#define	cret callp->param.aret.rvals.color_ret
+/*
+ *	bltocolor - get ASCII color name of label.
+ *
+ *	Entry	label = Sensitivity Level of color to get.
+ *		size  = Size of the color_name array.
+ *		color_name = Storage for ASCII color name string to be returned.
+ *
+ *	Exit	None.
+ *
+ *	Returns	NULL, If error (label encodings file not accessible,
+ *			   invalid label, no color for this label).
+ *		Address of color_name parameter containing ASCII color name
+ *			defined for the label.
+ *
+ *	Calls	__call_labeld(BLTOCOLOR), strlen.
+ */
+
+char *
+bltocolor_r(const blevel_t *label, size_t size, char *color_name)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(color_call_t, 0);
+	char	*colorp;
+
+	call.callop = BLTOCOLOR;
+	ccall.label = *label;
+
+	if ((__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) ||
+	    (callp->reterr != 0) ||
+	    (strlen(cret.color) >= size)) {
+
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (NULL);
+	}
+
+	colorp = strcpy(color_name, cret.color);
+
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (colorp);
+}  /* bltocolor_r */
+#undef	ccall
+#undef	cret
+
+/*
+ *	bltocolor - get ASCII color name of label.
+ *
+ *	Entry	label = Sensitivity Level of color to get.
+ *
+ *	Exit	None.
+ *
+ *	Returns	NULL, If error (label encodings file not accessible,
+ *			   invalid label, no color for this label).
+ *		Address of statically allocated string containing ASCII
+ *			color name defined for the classification contained
+ *			in label.
+ *
+ *	Uses	color.
+ *
+ *	Calls	bltocolor_r.
+ */
+
+char *
+bltocolor(const blevel_t *label)
+{
+	return (bltocolor_r(label, sizeof (color), color));
+}  /* bltocolor */
+
+blevel_t *
+blabel_alloc(void)
+{
+	return (m_label_alloc(MAC_LABEL));
+}
+
+void
+blabel_free(blevel_t *label_p)
+{
+	free(label_p);
+}
+
+size_t
+blabel_size(void)
+{
+	return (sizeof (blevel_t));
+}
+
+/*
+ *	getuserrange - get label range for user
+ *
+ *	Entry	username of user
+ *
+ *	Exit	None.
+ *
+ *	Returns	NULL, If memory allocation failure or userdefs failure.
+ *		otherwise returns the allocates m_range_t with the
+ *		user's min and max labels set.
+ */
+
+m_range_t *
+getuserrange(const char *username)
+{
+	char		*kv_str = NULL;
+	userattr_t 	*userp = NULL;
+	m_range_t 	*range;
+	int		err;
+
+	/*
+	 * Get some memory
+	 */
+
+	if ((range = malloc(sizeof (m_range_t))) == NULL) {
+		return (NULL);
+	}
+	if ((range->lower_bound = m_label_alloc(MAC_LABEL)) == NULL) {
+		free(range);
+		return (NULL);
+	}
+	if ((range->upper_bound = m_label_alloc(USER_CLEAR)) == NULL) {
+		m_label_free(range->lower_bound);
+		free(range);
+		return (NULL);
+	}
+	/*
+	 * Since user_attr entries are optional, start with
+	 * the system default values
+	 */
+	if ((userdefs(range->lower_bound, range->upper_bound)) == -1) {
+		m_label_free(range->lower_bound);
+		m_label_free(range->upper_bound);
+		free(range);
+		return (NULL);
+	}
+	/*
+	 * If the user has an explicit min_label or clearance,
+	 * then use it instead.
+	 */
+	if ((userp = getusernam(username)) == NULL) {
+		return (range);
+	}
+	if ((kv_str = kva_match(userp->attr, USERATTR_MINLABEL)) != NULL)
+		(void) stobsl(kv_str, range->lower_bound, NO_CORRECTION, &err);
+	if ((kv_str = kva_match(userp->attr, USERATTR_CLEARANCE)) != NULL)
+		(void) stobclear(kv_str, range->upper_bound, NO_CORRECTION,
+		    &err);
+	free_userattr(userp);
+	return (range);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/private.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,660 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	Label library contract private interfaces.
+ *
+ *	Binary labels to String labels with dimming word lists.
+ *	Dimming word list titles.
+ *	Default user labels.
+ */
+
+#include <locale.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <sys/mman.h>
+
+#include <tsol/label.h>
+
+#include "clnt.h"
+#include "labeld.h"
+
+/*
+ *	cvt memory:
+ *
+ * cvt:	char	*long_words[display_size];	Pointers to long words
+ *	char	*short_words[display_size];	Pointers to short words
+ * dim:	char	display[display_size];		Dim | Set
+ *
+ *	    strings associated with long and short words.
+ *
+ */
+
+/*
+ *	Sensitivity Label words.
+ */
+
+static	char *slcvt = NULL;
+static	int   slcvtsize = 0;
+static	char *sldim;
+
+static	char *slstring = NULL;
+static	int   slstringsize = 0;
+static	brange_t sbounds;
+
+/*
+ *	Clearance words.
+ */
+
+static	char *clrcvt = NULL;
+static	int   clrcvtsize = 0;
+static	char *clrdim;
+
+static	char *clrstring = NULL;
+static	int   clrstringsize = 0;
+static	brange_t cbounds;
+
+static
+int
+alloc_words(char **words, const size_t size)
+{
+	if (*words == NULL) {
+		if ((*words = malloc(size)) == NULL)
+			return (0);
+	} else {
+		if ((*words = realloc(*words, size)) == NULL) {
+			return (0);
+		}
+	}
+	return (1);
+}
+
+/*
+ *	build_strings - Build the static strings and dimming list for a
+ *			converted label.
+ *
+ *	Entry	new_string = Newly converted string.
+ *		new_words_size = Size of words associated with newly converted
+ *				 label.
+ *		number_of_words = Number of words associated with newly
+ *				  converted label.
+ *		full =	1, if static words lists to be updated.
+ *			0, if only string and dimming list to be updated.
+ *
+ *	Exit	static_string_size = Updated if needed.
+ *		static_string = Updated to new label string.
+ *		static_words_size = Updated if needed.
+ *		static_words = Updated to new words list, if needed.
+ *		static_dimming = Updated to new dimming state.
+ *		long_words = Updated to new long words pointers, if needed.
+ *		short_words = Updated to new short words pointers, if needed.
+ *
+ *
+ *	Returns	0, If unable to allocate memory.
+ *		1, If successful.
+ *
+ *	Calls	alloc_string, alloc_words, memcpy, strcpy, strlen.
+ */
+
+static
+int
+build_strings(int *static_string_size, char **static_string, char *new_string,
+    int *static_words_size, int new_words_size, char **static_words,
+    char **static_dimming, int number_of_words, char *long_words,
+    char *short_words, char *dimming_list, int full)
+{
+	char	**l;
+	char	**s;
+	char	*w;
+	char	*l_w = long_words;
+	char	*s_w = short_words;
+	int	i;
+	int	len;
+	int	newsize;
+
+	if (*static_string_size == 0) { /* Allocate string memory. */
+		if ((*static_string_size = alloc_string(static_string,
+		    *static_string_size, 'C')) == 0)
+			/* can't get string memory for string */
+			return (0);
+	}
+
+again:
+	if (*static_string_size < (int)strlen(new_string)+1) {
+		/* need longer string */
+		if ((newsize = alloc_string(static_string, *static_string_size,
+		    'C')) == 0)
+			/* can't get more string memory */
+			return (0);
+
+		*static_string_size += newsize;
+		goto again;
+	}
+	bcopy(new_string, *static_string, strlen(new_string) + 1);
+
+	if (full) {
+		if (*static_words_size < new_words_size &&
+		    !alloc_words(static_words, new_words_size)) {
+			/* can't get more words memory */
+			return (0);
+		} else {
+			*static_words_size = new_words_size;
+		}
+		/*LINTED*/
+		l = (char **)*static_words;
+		s = l + number_of_words;
+		*static_dimming = (char *)(s + number_of_words);
+		w = *static_dimming + number_of_words;
+		for (i = 0; i < number_of_words; i++) {
+			*l = w;
+			(void) strcpy(w, l_w);
+			w += (len = strlen(l_w) + 1);
+			l_w += len;
+			if (*s_w == '\000') {
+				*s = NULL;
+				s_w++;
+			} else {
+				*s = w;
+				(void) strcpy(w, s_w);
+				w += (len = strlen(s_w) + 1);
+				s_w += len;
+			}
+
+			l++;
+			s++;
+		}  /* for each word entry */
+	}  /* if (full) */
+
+	bcopy(dimming_list, *static_dimming, number_of_words);
+	return (1);
+}  /* build_strings */
+
+#define	bsfcall callp->param.acall.cargs.bslcvt_arg
+#define	bsfret callp->param.aret.rvals.bslcvt_ret
+/*
+ *	bslcvtfull - Convert Sensitivity Label and initialize static
+ *			information.
+ *
+ *	Entry	label = Sensitivity Label to convert and get dimming list.
+ *			This label should lie within the bounds or the
+ *			results may not be meaningful.
+ *		bounds = Lower and upper bounds for words lists. Must be
+ *			dominated by clearance.
+ *		flags = VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = ASCII coded Sensitivity Label.
+ *		long_words = Array of pointers to visible long word names.
+ *		short_words = Array of pointers to visible short word names.
+ *		display = Array of indicators as to whether the word is present
+ *			  in the converted label (CVT_SET), and/or changeable
+ *			  (CVT_DIM).
+ *		first_compartment = Zero based index of first compartment.
+ *		display_size = Number of entries in the display/words lists.
+ *
+ *	Returns	-1, If unable to access label encodings database, or
+ *			invalid label.
+ *		 0, If unable to allocate static memory.
+ *		 1, If successful.
+ *
+ *	Calls	RPC - LABELS_BSLCONVERT, STTBLEVEL, SETBSLABEL, TCLNT,
+ *			build_strings, clnt_call, clnt_perror.
+ *
+ *	Uses	sbounds, slrcvt, slrcvtsize, slrdim, slrstring,
+ *			slrstringsize.
+ */
+
+int
+bslcvtfull(const bslabel_t *label, const blrange_t *bounds, int flags,
+    char **string, char **long_words[], char **short_words[], char *display[],
+    int *first_compartment, int *display_size)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bslcvt_call_t, 0);
+	int	new_words_size;
+	int	rval;
+
+	call.callop = BSLCVT;
+	bsfcall.label = *label;
+	bsfcall.bounds.upper_bound = *bounds->upper_bound;
+	bsfcall.bounds.lower_bound = *bounds->lower_bound;
+	bsfcall.flags = LABELS_FULL_CONVERT;
+	set_label_view(&bsfcall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
+#ifdef	DEBUG
+		(void) fprintf(stderr, "No label server.\n");
+#endif	/* DEBUG */
+		return (-1);
+	} else if (rval != SUCCESS) {
+		return (-1);
+	} else {
+		if (callp->reterr != 0)
+			return (-1);
+	}
+
+	*first_compartment = bsfret.first_comp;
+	*display_size = bsfret.d_len;
+
+	new_words_size = bsfret.l_len + bsfret.s_len + bsfret.d_len +
+	    (2 * sizeof (char *)) * bsfret.d_len;
+
+	if (build_strings(&slstringsize, &slstring, &bsfret.buf[bsfret.string],
+	    &slcvtsize, new_words_size, &slcvt, &sldim, bsfret.d_len,
+	    &bsfret.buf[bsfret.lwords], &bsfret.buf[bsfret.swords],
+	    &bsfret.buf[bsfret.dim], 1) != 1) {
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+
+	/* save for bslcvt call */
+	sbounds.upper_bound = *bounds->upper_bound;
+	sbounds.lower_bound = *bounds->lower_bound;
+
+	*string = slstring;
+	*display = sldim;
+	/*LINTED*/
+	*long_words = (char **)slcvt;
+	/*LINTED*/
+	*short_words = (char **)(slcvt + *display_size * sizeof (char *));
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (1);
+}  /* bslcvtfull */
+#undef	bsfcall
+#undef	bsfret
+
+#define	bsccall callp->param.acall.cargs.bslcvt_arg
+#define	bscret callp->param.aret.rvals.bslcvt_ret
+/*
+ *	bslcvt - Convert Sensitivity Label and update dimming information.
+ *
+ *	Entry	label = Sensitivity Label to convert and get dimming list.
+ *			This label should lie within the bounds of the
+ *			corresponding bslcvtfull call or the results may
+ *			not be meaningful.
+ *		flags = VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = ASCII coded Sensitivity Label.
+ *		display = Array of indicators as to whether the word is present
+ *			  in the converted label (CVT_SET), and/or changeable
+ *			  (CVT_DIM).
+ *
+ *	Returns	-1, If unable to access label encodings database, or
+ *			invalid label.
+ *		 0, If unable to allocate static memory.
+ *		 1, If successful.
+ *
+ *	Calls	RPC - LABELS_BSLCONVERT, SETBLEVEL, SETBSLABEL, build_strings
+ *			clnt_call, clnt_perror.
+ *
+ *	Uses	sbounds, slrdim, slrstring.
+ */
+
+int
+bslcvt(const bslabel_t *label, int flags, char **string, char *display[])
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bslcvt_call_t, 0);
+	int	rval;
+
+	if (slcvt == NULL)
+		return (-1);	/* conversion not initialized */
+
+	call.callop = BSLCVT;
+	bsccall.label = *label;
+	bsccall.bounds = sbounds;	/* save from last bslcvtfull() call */
+	bsccall.flags = 0;
+	set_label_view(&bsccall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
+#ifdef	DEBUG
+		(void) fprintf(stderr, "No label server.\n");
+#endif	/* DEBUG */
+		return (-1);
+	} else if (rval != SUCCESS) {
+		return (-1);
+	} else {
+		if (callp->reterr != 0)
+			return (-1);
+	}
+
+	if (build_strings(&slstringsize, &slstring, &bscret.buf[bscret.string],
+	    &slcvtsize, 0, &slcvt, &sldim, bscret.d_len,
+	    &bscret.buf[bscret.lwords], &bscret.buf[bscret.swords],
+	    &bscret.buf[bscret.dim], 0) != 1) {
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+
+	*string = slstring;
+	*display = sldim;
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (1);
+}  /* bslcvt */
+#undef	bsccall
+#undef	bscret
+
+#define	bcfcall callp->param.acall.cargs.bclearcvt_arg
+#define	bcfret callp->param.aret.rvals.bclearcvt_ret
+/*
+ *	bclearcvtfull - Convert Clearance and initialize static information.
+ *
+ *	Entry	clearance = Clearance to convert and get dimming list.
+ *			    This clearance should lie within the bounds or
+ *			    the results may not be meaningful.
+ *		bounds = Lower and upper bounds for words lists. Must be
+ *			dominated by clearance.
+ *		flags = VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = ASCII coded Clearance.
+ *		long_words = Array of pointers to visible long word names.
+ *		short_words = Array of pointers to visible short word names.
+ *		display = Array of indicators as to whether the word is present
+ *			  in the converted label (CVT_SET), and/or changeable
+ *			  (CVT_DIM).
+ *		first_compartment = Zero based index of first compartment.
+ *		display_size = Number of entries in the display/words lists.
+ *
+ *	Returns	-1, If unable to access label encodings database, or
+ *			invalid label.
+ *		 0, If unable to allocate static memory.
+ *		 1, If successful.
+ *
+ *	Calls	RPC - LABELS_BCLEARCONVERT, SETBCLEAR, SETBLEVEL, TCLNT,
+ *			build_strings, clnt_call, clnt_perror.
+ *
+ *	Uses	cbounds, clrcvt, clrcvtsize, clrdim, clrstring,
+ *			clrstringsize.
+ */
+
+int
+bclearcvtfull(const bclear_t *clearance, const blrange_t *bounds,
+    int flags, char **string, char **long_words[], char **short_words[],
+    char *display[], int *first_compartment, int *display_size)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bclearcvt_call_t, 0);
+	int	new_words_size;
+	int	rval;
+
+	call.callop = BCLEARCVT;
+	bcfcall.clear = *clearance;
+	bcfcall.bounds.upper_bound = *bounds->upper_bound;
+	bcfcall.bounds.lower_bound = *bounds->lower_bound;
+	bcfcall.flags = LABELS_FULL_CONVERT;
+	set_label_view(&bcfcall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
+#ifdef	DEBUG
+		(void) fprintf(stderr, "No label server.\n");
+#endif	/* DEBUG */
+		return (-1);
+	} else if (rval != SUCCESS) {
+		return (-1);
+	} else {
+		if (callp->reterr != 0)
+			return (-1);
+	}
+
+	*first_compartment = bcfret.first_comp;
+	*display_size = bcfret.d_len;
+
+	new_words_size = bcfret.l_len + bcfret.s_len + bcfret.d_len +
+	    (2 * sizeof (char *)) * bcfret.d_len;
+
+	if (build_strings(&clrstringsize, &clrstring,
+	    &bcfret.buf[bcfret.string],
+	    &clrcvtsize, new_words_size, &clrcvt,
+	    &clrdim, bcfret.d_len,
+	    &bcfret.buf[bcfret.lwords], &bcfret.buf[bcfret.swords],
+	    &bcfret.buf[bcfret.dim], 1) != 1) {
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+
+	/* save for bclearcvt call */
+	cbounds.upper_bound = *bounds->upper_bound;
+	cbounds.lower_bound = *bounds->lower_bound;
+
+	*string = clrstring;
+	*display = clrdim;
+	/*LINTED*/
+	*long_words = (char **)clrcvt;
+	/*LINTED*/
+	*short_words = (char **)(clrcvt + *display_size * sizeof (char *));
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (1);
+}  /* bclearcvtfull */
+#undef	bcfcall
+#undef	bcfret
+
+#define	bcccall callp->param.acall.cargs.bclearcvt_arg
+#define	bccret callp->param.aret.rvals.bclearcvt_ret
+/*
+ *	bclearcvt - Convert Clearance and update dimming inforamtion.
+ *
+ *	Entry	clearance = Clearance to convert and get dimming list.
+ *			    This clearance should lie within the bounds of the
+ *			    corresponding bclearcvtfull call or the results may
+ *			    not be meaningful.
+ *		flags = VIEW_INTERNAL, don't promote/demote admin low/high.
+ *			VIEW_EXTERNAL, promote/demote admin low/high.
+ *
+ *	Exit	string = ASCII coded Clearance.
+ *		display = Array of indicators as to whether the word is present
+ *			  in the converted label (CVT_SET), and/or changeable
+ *			  (CVT_DIM).
+ *
+ *	Returns	-1, If unable to access label encodings database, or
+ *			invalid label.
+ *		 0, If unable to allocate static memory.
+ *		 1, If successful.
+ *
+ *	Calls	RPC - LABELS_BCLEARCONVERT, SETBCLEAR, SETBLEVEL, build_strings,
+ *			clnt_call, clnt_perror.
+ *
+ *	Uses	cbounds, clrdim, clrstring.
+ */
+
+int
+bclearcvt(const bclear_t *clearance, int flags, char **string,
+    char *display[])
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(bclearcvt_call_t, 0);
+	int	rval;
+
+	if (clrcvt == NULL)
+		return (-1);	/* conversion not initialized */
+
+	call.callop = BCLEARCVT;
+	bcccall.clear = *clearance;
+	bcccall.bounds = cbounds;	/* save from last bslcvtfull() call */
+	bcccall.flags = 0;
+	set_label_view(&bcccall.flags, flags);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
+#ifdef	DEBUG
+		(void) fprintf(stderr, "No label server.\n");
+#endif	/* DEBUG */
+		return (-1);
+	} else if (rval != SUCCESS) {
+		return (-1);
+	} else {
+		if (callp->reterr != 0)
+			return (-1);
+	}
+
+	if (build_strings(&clrstringsize, &clrstring,
+	    &bccret.buf[bccret.string],
+	    &clrcvtsize, 0, &clrcvt, &clrdim, bccret.d_len,
+	    &bccret.buf[bccret.lwords], &bccret.buf[bccret.swords],
+	    &bccret.buf[bccret.dim], 0) != 1) {
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+
+	*string = clrstring;
+	*display = clrdim;
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (1);
+}  /* bclearcvt */
+#undef	bcccall
+#undef	bccret
+
+#define	lfret callp->param.aret.rvals.fields_ret
+/*
+ *	labelfields - Return names for the label fields.
+ *
+ *	Entry	None
+ *
+ *	Exit	fields = Updated.
+ *
+ *	Returns	-1, If unable to access label encodings file, or
+ *			labels server failure.
+ *		 0, If unable to allocate memory.
+ *		 1, If successful.
+ *
+ *	Calls __call_labeld(LABELFIELDS).
+ */
+
+int
+labelfields(struct name_fields *fields)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(fields_call_t, 0);
+	int	rval;
+
+	call.callop = LABELFIELDS;
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) != SUCCESS) {
+
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (-1);
+	}
+
+	/* unpack results */
+
+	if ((fields->class_name = strdup(&lfret.buf[lfret.classi])) == NULL) {
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+	if ((fields->comps_name = strdup(&lfret.buf[lfret.compsi])) == NULL) {
+		free(fields->class_name);
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+	if ((fields->marks_name = strdup(&lfret.buf[lfret.marksi])) == NULL) {
+		free(fields->class_name);
+		free(fields->comps_name);
+		if (callp != &call)
+			/* release return buffer */
+			(void) munmap((void *)callp, bufsize);
+		return (0);
+	}
+
+	if (callp != &call)
+		/* release return buffer */
+		(void) munmap((void *)callp, bufsize);
+	return (rval);
+}  /* labelfields */
+#undef	lfret
+
+#define	udret callp->param.aret.rvals.udefs_ret
+/*
+ *	userdefs - Get default user Sensitivity Label and Clearance.
+ *
+ *	Entry   None.
+ *
+ *	Exit	sl = default user Sensitivity Label.
+ *		clear = default user Clearance.
+ *
+ *	Returns -1, If unable to access label encodings file, or
+ *			labels server failure.
+ *		1, If successful.
+ *
+ *	Calls	__call_labeld(UDEFS).
+ */
+
+int
+userdefs(bslabel_t *sl, bclear_t *clear)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(udefs_call_t, 0);
+	int	rval;
+
+	call.callop = UDEFS;
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) != SUCCESS) {
+		/* process error */
+
+		return (-1);
+	}
+
+	*sl = udret.sl;
+	*clear = udret.clear;
+	return (rval);
+}  /* userdefs */
+#undef	udret
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/privlib.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,179 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include 	<errno.h>
+#include 	<priv.h>
+#include 	<sys/tsol/priv.h>
+#include 	<sys/varargs.h>
+
+/*
+ * set_effective_priv(op, num_priv, priv_id1, priv_id2, ... )
+ *
+ * Library routine to enable a user process to set its effective
+ * privilege set appropriately using a single call.  User is
+ * required to specify the number of privilege ids that follow as
+ * arguments, rather than depending on the compiler to terminate
+ * the argument list with a NULL, which may be compiler-dependent.
+ */
+int
+set_effective_priv(priv_op_t op, int num_priv, ...)
+{
+	priv_set_t *priv_set;
+	priv_t priv_id;
+	va_list ap;
+	int	status;
+
+	priv_set = priv_allocset();
+	PRIV_EMPTY(priv_set);
+
+	va_start(ap, num_priv);
+	while (num_priv--) {
+		char	*priv_name;
+		/*
+		 * Do sanity checking on priv_id's here to assure
+		 * valid inputs to privilege macros.  This checks
+		 * num_priv argument as well.
+		 */
+		priv_id = va_arg(ap, priv_t);
+		priv_name = (char *)priv_getbynum((int)(uintptr_t)priv_id);
+		if (priv_name == NULL) {
+			errno = EINVAL;
+			priv_freeset(priv_set);
+			return (-1);
+		}
+		(void) priv_addset(priv_set, priv_name);
+	}
+	va_end(ap);
+
+	/*
+	 * Depend on system call to do sanity checking on "op"
+	 */
+	status = setppriv(op, PRIV_EFFECTIVE, priv_set);
+	priv_freeset(priv_set);
+	return (status);
+
+} /* set_effective_priv() */
+
+
+
+
+/*
+ * set_inheritable_priv(op, num_priv, priv_id1, priv_id2, ... )
+ *
+ * Library routine to enable a user process to set its inheritable
+ * privilege set appropriately using a single call.  User is
+ * required to specify the number of privilege ids that follow as
+ * arguments, rather than depending on the compiler to terminate
+ * the argument list with a NULL, which may be compiler-dependent.
+ */
+int
+set_inheritable_priv(priv_op_t op, int num_priv, ...)
+{
+	priv_set_t *priv_set;
+	priv_t priv_id;
+	va_list ap;
+	int	status;
+
+	priv_set = priv_allocset();
+
+	PRIV_EMPTY(priv_set);
+
+	va_start(ap, num_priv);
+	while (num_priv--) {
+		/*
+		 * Do sanity checking on priv_id's here to assure
+		 * valid inputs to privilege macros.  This checks
+		 * num_priv argument as well.
+		 */
+		priv_id = va_arg(ap, priv_t);
+		if ((char *)priv_getbynum((int)(uintptr_t)priv_id) == NULL) {
+			errno = EINVAL;
+			priv_freeset(priv_set);
+			return (-1);
+		}
+		(void) PRIV_ASSERT(priv_set, priv_id);
+	}
+	va_end(ap);
+
+	/*
+	 * Depend on system call to do sanity checking on "op"
+	 */
+	status = setppriv(op, PRIV_INHERITABLE, priv_set);
+	priv_freeset(priv_set);
+	return (status);
+
+} /* set_inheritable_priv() */
+
+
+
+
+/*
+ * set_permitted_priv(op, num_priv, priv_id1, priv_id2, ... )
+ *
+ * Library routine to enable a user process to set its permitted
+ * privilege set appropriately using a single call.  User is
+ * required to specify the number of privilege ids that follow as
+ * arguments, rather than depending on the compiler to terminate
+ * the argument list with a NULL, which may be compiler-dependent.
+ */
+int
+set_permitted_priv(priv_op_t op, int num_priv, ...)
+{
+	priv_set_t *priv_set;
+	priv_t priv_id;
+	va_list ap;
+	int	status;
+
+	priv_set = priv_allocset();
+
+	PRIV_EMPTY(priv_set);
+
+	va_start(ap, num_priv);
+	while (num_priv--) {
+		/*
+		 * Do sanity checking on priv_id's here to assure
+		 * valid inputs to privilege macros.  This checks
+		 * num_priv argument as well.
+		 */
+		priv_id = va_arg(ap, priv_t);
+		if ((char *)priv_getbynum((int)(uintptr_t)priv_id) == NULL) {
+			errno = EINVAL;
+			priv_freeset(priv_set);
+			return (-1);
+		}
+		(void) PRIV_ASSERT(priv_set, priv_id);
+	}
+	va_end(ap);
+
+	/*
+	 * Depend on system call to do sanity checking on "op"
+	 */
+	status = setppriv(op, PRIV_PERMITTED, priv_set);
+	priv_freeset(priv_set);
+	return (status);
+
+} /* set_permitted_priv() */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/setflabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,309 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	Change the label of a file
+ */
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+
+#include <tsol/label.h>
+
+#include "labeld.h"
+#include <sys/tsol/label_macro.h>
+
+#include <sys/types.h>
+
+#include <zone.h>
+#include <sys/zone.h>
+#include <sys/param.h>
+#include <string.h>
+
+static int abspath(char *, const char *, char *);
+
+/*
+ * setflabel(3TSOL) - set file label
+ *
+ * This is the library interface to the door call.
+ */
+
+#define	clcall callp->param.acall.cargs.setfbcl_arg
+#define	clret callp->param.aret.rvals.setfbcl_ret
+/*
+ *
+ *	Exit	error = If error reported, the error indicator,
+ *				-1, Unable to access label encodings file;
+ *				 0, Invalid binary label passed;
+ *				>0, Position after the first character in
+ *				    string of error, 1 indicates entire string.
+ *			Otherwise, unchanged.
+ *
+ *	Returns	0, If error.
+ *		1, If successful.
+ *
+ *	Calls	__call_labeld(SETFLABEL)
+ *
+ */
+
+int
+setflabel(const char *path, m_label_t *label)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize;
+	size_t	path_len;
+	static char	cwd[MAXPATHLEN];
+	char		canon[MAXPATHLEN];
+
+
+	/*
+	 * If path is relative and we haven't already determined the current
+	 * working directory, do so now.  Calculating the working directory
+	 * here lets us do the work once, instead of (potentially) repeatedly
+	 * in realpath().
+	 */
+	if (*path != '/' && cwd[0] == '\0') {
+		if (getcwd(cwd, MAXPATHLEN) == NULL) {
+			cwd[0] = '\0';
+			return (-1);
+		}
+	}
+	/*
+	 * Find an absolute pathname in the native file system name space that
+	 * corresponds to path, stuffing it into canon.
+	 */
+	if (abspath(cwd, path, canon) < 0)
+		return (-1);
+
+	path_len = strlen(canon) + 1;
+
+	datasize = CALL_SIZE(setfbcl_call_t, path_len - BUFSIZE);
+	datasize += 2; /* PAD */
+
+	if (datasize > bufsize) {
+		if ((callp = (labeld_data_t *)malloc(datasize)) == NULL) {
+			return (-1);
+		}
+		bufsize = datasize;
+	}
+
+	callp->callop = SETFLABEL;
+
+	clcall.sl = *label;
+	(void) strcpy(clcall.pathname, canon);
+
+	if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) {
+		int err = callp->reterr;
+
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/*
+		 * reterr == 0, OK,
+		 * reterr < 0, invalid binary label,
+		 */
+		if (err == 0) {
+			if (clret.status > 0) {
+				errno = clret.status;
+				return (-1);
+			} else {
+				return (0);
+			}
+		} else if (err < 0) {
+			err = 0;
+		}
+		errno = ECONNREFUSED;
+		return (-1);
+	} else {
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/* server not present */
+		errno = ECONNREFUSED;
+		return (-1);
+	}
+}  /* setflabel */
+
+#undef	clcall
+#undef	clret
+
+#define	clcall callp->param.acall.cargs.zcopy_arg
+#define	clret callp->param.aret.rvals.zcopy_ret
+/*
+ *
+ *	Exit	status = result of zone copy request
+ *				-1, Copy not confirmed
+ *			Otherwise, unchanged.
+ *
+ *	Returns	0, If error.
+ *		1, If successful.
+ *
+ *	Calls	__call_labeld(ZCOPY)
+ *
+ */
+int
+zonecopy(m_label_t *src_win_sl, char *remote_dir, char *filename,
+    char *local_dir, int  transfer_mode)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t		bufsize = sizeof (labeld_data_t);
+	size_t		datasize;
+	size_t		strings;
+	size_t		remote_dir_len;
+	size_t		filename_len;
+	size_t		local_dir_len;
+	size_t		display_len;
+	char		*display;
+
+	remote_dir_len = strlen(remote_dir) + 1;
+	filename_len = strlen(filename) + 1;
+	local_dir_len = strlen(local_dir) + 1;
+
+	if ((display = getenv("DISPLAY")) == NULL)
+		display = "";
+	display_len = strlen(display) + 1;
+
+	strings = remote_dir_len + filename_len + local_dir_len + display_len;
+
+	datasize = CALL_SIZE(zcopy_call_t, strings - BUFSIZE);
+
+	datasize += 4; /* PAD */
+
+	if (datasize > bufsize) {
+		if ((callp = (labeld_data_t *)malloc(datasize)) == NULL) {
+			return (NULL);
+		}
+		bufsize = datasize;
+	}
+
+	strings = 0;
+	callp->callop = ZCOPY;
+
+	clcall.src_win_sl = *src_win_sl;
+	clcall.transfer_mode = transfer_mode;
+	clcall.remote_dir = strings;
+	strings += remote_dir_len;
+	clcall.filename = strings;
+	strings += filename_len;
+	clcall.local_dir = strings;
+	strings += local_dir_len;
+	clcall.display = strings;
+
+	(void) strcpy(&clcall.buf[clcall.remote_dir], remote_dir);
+	(void) strcpy(&clcall.buf[clcall.filename], filename);
+	(void) strcpy(&clcall.buf[clcall.local_dir], local_dir);
+	(void) strcpy(&clcall.buf[clcall.display], display);
+
+	if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) {
+		int err = callp->reterr;
+
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/*
+		 * reterr == 0, OK,
+		 * reterr < 0, transer not confirmed
+		 */
+		if (err == 0) {
+			return (clret.status);
+		} else if (err < 0) {
+			err = 0;
+		}
+		return (PIPEMSG_CANCEL);
+	} else {
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/* server not present */
+		return (PIPEMSG_CANCEL);
+	}
+}
+
+/*
+ * Convert the path given in raw to canonical, absolute, symlink-free
+ * form, storing the result in the buffer named by canon, which must be
+ * at least MAXPATHLEN bytes long.  If wd is non-NULL, assume that it
+ * points to a path for the current working directory and use it instead
+ * of invoking getcwd; accepting this value as an argument lets our caller
+ * cache the value, so that realpath (called from this routine) doesn't have
+ * to recalculate it each time it's given a relative pathname.
+ *
+ * Return 0 on success, -1 on failure.
+ */
+int
+abspath(char *wd, const char *raw, char *canon)
+{
+	char		absbuf[MAXPATHLEN];
+
+	/*
+	 * Preliminary sanity check.
+	 */
+	if (raw == NULL || canon == NULL)
+		return (-1);
+
+	/*
+	 * If the path is relative, convert it to absolute form,
+	 * using wd if it's been supplied.
+	 */
+	if (raw[0] != '/') {
+		char	*limit = absbuf + sizeof (absbuf);
+		char	*d;
+
+		/* Fill in working directory. */
+		if (wd != NULL)
+			(void) strncpy(absbuf, wd, sizeof (absbuf));
+		else if (getcwd(absbuf, strlen(absbuf)) == NULL)
+			return (-1);
+
+		/* Add separating slash. */
+		d = absbuf + strlen(absbuf);
+		if (d < limit)
+			*d++ = '/';
+
+		/* Glue on the relative part of the path. */
+		while (d < limit && (*d++ = *raw++))
+			continue;
+
+		raw = absbuf;
+	}
+
+	/*
+	 * Call realpath to canonicalize and resolve symlinks.
+	 */
+	return (realpath(raw, canon) == NULL ? -1 : 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/stob.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,312 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *	String to binary label translations.
+ */
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <tsol/label.h>
+
+#include "labeld.h"
+#include <sys/tsol/label_macro.h>
+
+#undef	CALL_SIZE
+#define	CALL_SIZE(type, buf)	(size_t)(sizeof (type) - BUFSIZE + sizeof (int)\
+	+ (buf))
+
+#if	!defined(TEXT_DOMAIN)		/* should be defined by Makefiles */
+#define	TEXT_DOMAIN "SYS_TEST"
+#endif	/* TEXT_DOMAIN */
+
+/* short hands */
+
+#define	IS_ADMIN_LOW(sl) \
+	((strncasecmp(sl, ADMIN_LOW, (sizeof (ADMIN_LOW) - 1)) == 0))
+
+#define	IS_ADMIN_HIGH(sh) \
+	((strncasecmp(sh, ADMIN_HIGH, (sizeof (ADMIN_HIGH) - 1)) == 0))
+
+#define	ISHEX(f, s) \
+	(((((f) & NEW_LABEL) == ((f) | NEW_LABEL)) || \
+	(((f) & NO_CORRECTION) == ((f) | NO_CORRECTION))) && \
+	(((s)[0] == '0') && (((s)[1] == 'x') || ((s)[1] == 'X'))))
+
+#define	slcall callp->param.acall.cargs.stobsl_arg
+#define	slret callp->param.aret.rvals.stobsl_ret
+/*
+ *	stobsl - Translate Sensitivity Label string to a Binary Sensitivity
+ *		Label.
+ *
+ *	Entry	string = Sensitivity Label string to be translated.
+ *		label = Address of Binary Sensitivity Label to be initialized or
+ *			updated.
+ *		flags = Flags to control translation:
+ *			NO_CORRECTION implies NEW_LABEL.
+ *			NEW_LABEL, Initialize the label to a valid empty
+ *				Sensitivity Label structure.
+ *			NO_CORRECTION, Initialize the label to a valid
+ *				empty Sensitivity Label structure.
+ *				Prohibit correction to the Sensitivity Label.
+ *			Other, pass existing Sensitivity Label through for
+ *				modification.
+ *
+ *	Exit	label = Translated (updated) Binary Sensitivity Label.
+ *		error = If error reported, the error indicator,
+ *				-1, Unable to access label encodings file;
+ *				 0, Invalid binary label passed;
+ *				>0, Position after the first character in
+ *				    string of error, 1 indicates entire string.
+ *			Otherwise, unchanged.
+ *
+ *	Returns	0, If error.
+ *		1, If successful.
+ *
+ *	Calls	__call_labeld(STOBSL), ISHEX, htobsl, strlen,
+ *			isspace,
+ *			strncasecmp.
+ *
+ *	Uses	ADMIN_HIGH, ADMIN_LOW.
+ */
+
+int
+stobsl(const char *string, bslabel_t *label, int flags, int *error)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(stobsl_call_t, strlen(string) + 1);
+	int	rval;
+	char	*s = (char *)string;
+
+	while (isspace(*s))
+		s++;
+	/* accept a leading '[' */
+	if (*s == '[') {
+		s++;
+		while (isspace(*s))
+			s++;
+	}
+	if (ISHEX(flags, s)) {
+		if (htobsl(s, label)) {
+			return (1);
+		} else {
+			if (error != NULL)
+				*error = 1;
+			return (0);
+		}
+	}
+
+	if (datasize > bufsize) {
+		if ((callp = malloc(datasize)) == NULL) {
+			if (error != NULL)
+				*error = -1;
+			return (0);
+		}
+		bufsize = datasize;
+	}
+	callp->callop = STOBSL;
+	slcall.flags  = (flags&NEW_LABEL) ? LABELS_NEW_LABEL : 0;
+	slcall.flags |= (flags&NO_CORRECTION) ? LABELS_FULL_PARSE : 0;
+	slcall.label = *label;
+	(void) strcpy(slcall.string, string);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
+		int err = callp->reterr;
+
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/*
+		 * reterr == 0, OK,
+		 * reterr < 0, invalid binary label,
+		 * reterr > 0 error position, 1 == whole string
+		 */
+		if (err == 0) {
+			*label = slret.label;
+			return (1);
+		} else if (err < 0) {
+			err = 0;
+		}
+		if (error != NULL)
+			*error = err;
+		return (0);
+	} else if (rval == NOSERVER) {
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/* server not present */
+		/* special case Admin High and Admin Low */
+		if (IS_ADMIN_LOW(s)) {
+			BSLLOW(label);
+		} else if (IS_ADMIN_HIGH(s)) {
+			BSLHIGH(label);
+		} else {
+			goto err1;
+		}
+		return (1);
+	}
+	if (callp != &call) {
+		/* free allocated buffer */
+		free(callp);
+	}
+err1:
+	if (error != NULL)
+		*error = -1;
+	return (0);
+}  /* stobsl */
+#undef	slcall
+#undef	slret
+
+#define	clrcall callp->param.acall.cargs.stobclear_arg
+#define	clrret callp->param.aret.rvals.stobclear_ret
+/*
+ *	stobclear - Translate Clearance string to a Binary Clearance.
+ *
+ *	Entry	string = Clearance string to be translated.
+ *		clearance = Address of Binary Clearance to be initialized or
+ *			updated.
+ *		flags = Flags to control translation:
+ *			NO_CORRECTION implies NEW_LABEL.
+ *			NEW_LABEL, Initialize the label to a valid empty
+ *				Sensitivity Label structure.
+ *			NO_CORRECTION, Initialize the label to a valid
+ *				empty Sensitivity Label structure.
+ *				Prohibit correction to the Sensitivity Label.
+ *			Other, pass existing Sensitivity Label through for
+ *				modification.
+ *
+ *	Exit	clearance = Translated (updated) Binary Clearance.
+ *		error = If error reported, the error indicator,
+ *				-1, Unable to access label encodings file;
+ *				 0, Invalid binary label passed;
+ *				>0, Position after the first character in
+ *				    string of error, 1 indicates entire string.
+ *			Otherwise, unchanged.
+ *
+ *	Returns	0, If error.
+ *		1, If successful.
+ *
+ *	Calls	__call_labeld(STOBCLEAR), ISHEX, htobsl, strlen,
+ *			isspace,
+ *			strncasecmp.
+ *
+ *	Uses	ADMIN_HIGH, ADMIN_LOW.
+ */
+
+int
+stobclear(const char *string, bclear_t *clearance, int flags, int *error)
+{
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t	bufsize = sizeof (labeld_data_t);
+	size_t	datasize = CALL_SIZE(callp->param.acall, strlen(string) + 1);
+	int	rval;
+
+	if (ISHEX(flags, string)) {
+		if (htobclear(string, clearance)) {
+			return (1);
+		} else {
+			if (error != NULL)
+				*error = 1;
+			return (0);
+		}
+	}
+
+	if (datasize > bufsize) {
+		if ((callp = malloc(datasize)) == NULL) {
+			if (error != NULL)
+				*error = -1;
+			return (0);
+		}
+		bufsize = datasize;
+	}
+	callp->callop = STOBCLEAR;
+	clrcall.flags  = (flags&NEW_LABEL) ? LABELS_NEW_LABEL : 0;
+	clrcall.flags |= (flags&NO_CORRECTION) ? LABELS_FULL_PARSE : 0;
+	clrcall.clear = *clearance;
+	(void) strcpy(clrcall.string, string);
+
+	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
+		int err = callp->reterr;
+
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/*
+		 * reterr == 0, OK,
+		 * reterr < 0, invalid binary label,
+		 * reterr > 0 error position, 1 == whole string
+		 */
+		if (err == 0) {
+			*clearance = clrret.clear;
+			return (1);
+		} else if (err < 0) {
+			err = 0;
+		}
+		if (error != NULL)
+			*error = err;
+		return (0);
+	} else if (rval == NOSERVER) {
+		char *s = (char *)string;
+
+		if (callp != &call) {
+			/* free allocated buffer */
+			free(callp);
+		}
+		/* server not present */
+		/* special case Admin High and Admin Low */
+		while (isspace(*s))
+			s++;
+		if (IS_ADMIN_LOW(s)) {
+			BCLEARLOW(clearance);
+		} else if (IS_ADMIN_HIGH(s)) {
+			BCLEARHIGH(clearance);
+		} else {
+			goto err1;
+		}
+		return (1);
+	}
+	if (callp != &call) {
+		/* free allocated buffer */
+		free(callp);
+	}
+err1:
+	if (error != NULL)
+		*error = -1;
+	return (0);
+}  /* stobclear */
+#undef	clrcall
+#undef	clrret
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/stol.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,394 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <sys/mman.h>
+#include <sys/tsol/label_macro.h>
+
+#include <tsol/label.h>
+
+#include "clnt.h"
+#include "labeld.h"
+
+#define	IS_LOW(s) \
+	((strncasecmp(s, ADMIN_LOW, (sizeof (ADMIN_LOW) - 1)) == 0) && \
+	(s[sizeof (ADMIN_LOW) - 1] == '\0'))
+#define	IS_HIGH(s) \
+	((strncasecmp(s, ADMIN_HIGH, (sizeof (ADMIN_HIGH) - 1)) == 0) && \
+	(s[sizeof (ADMIN_HIGH) - 1] == '\0'))
+#define	IS_HEX(f, s) \
+	(((((f) == L_NO_CORRECTION)) || ((f) == L_DEFAULT)) && \
+	(((s)[0] == '0') && (((s)[1] == 'x') || ((s)[1] == 'X'))))
+
+static boolean_t
+unhex(char **h, uchar_t *l, int len)
+{
+	char	*hx = *h;
+	char	ch;
+	uchar_t	byte;
+
+	for (; len--; ) {
+		ch = *hx++;
+		if (!isxdigit(ch))
+			return (B_FALSE);
+		if (isdigit(ch))
+			byte = ch - '0';
+		else
+			byte = ch - (isupper(ch) ? 'A' - 10 : 'a' - 10);
+		byte <<= 4;
+		ch = *hx++;
+		if (isdigit(ch))
+			byte |= ch - '0';
+		else
+			byte |= ch - (isupper(ch) ? 'A' - 10 : 'a' - 10);
+		*l++ = byte;
+	}
+	*h = hx;
+	return (B_TRUE);
+}
+
+/*
+ * Formats accepted:
+ * 0x + 4 class + 64 comps + end of string
+ * 0x + 4 class + '-' + ll + '-' + comps + end of string
+ * ll = number of words to fill out the entire comps field
+ *      presumes trailing zero for comps
+ *
+ * So in the case of 256 comps (i.e., 8 compartment words):
+ * 0x0006-08-7ff3f
+ * 0x + Classification + Compartments + end of string
+ * 0[xX]hhh...
+ */
+
+static int
+htol(char *s, m_label_t *l)
+{
+	char	*h = &s[2];	/* skip 0[xX] */
+	uchar_t *lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_lclass);
+	size_t	len = sizeof (_mac_label_impl_t) - 4;
+	int	bytes;
+
+	/* unpack classification */
+	if (!unhex(&h, lp, 2)) {
+		goto error;
+	}
+	lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_comps);
+	if (LCLASS(l) < LOW_CLASS ||
+	    LCLASS(l) > HIGH_CLASS) {
+		goto error;
+	}
+	if (h[0] == '-' && h[3] == '-') {
+		uchar_t size;
+
+		/* length specified of internal text label */
+		h++;	/* skip '-' */
+		if (!unhex(&h, &size, 1)) {
+			goto error;
+		}
+		size *= sizeof (uint32_t);	/* words to bytes */
+		if (size > len) {
+			/*
+			 * internal label greater than will fit in current
+			 * binary.
+			 */
+			goto error;
+		}
+		bzero(lp, len);
+		h++;	/* skip '-' */
+		bytes = strlen(h)/2;
+	} else {
+		bytes = (strlen(h) + 1)/2;
+	}
+	if ((bytes > len) || !unhex(&h, lp, bytes)) {
+		goto error;
+	}
+	return (0);
+error:
+	errno = EINVAL;
+	return (-1);
+}
+
+static int
+convert_id(m_label_type_t t)
+{
+	switch (t) {
+	case MAC_LABEL:
+		return (SUN_MAC_ID);
+	case USER_CLEAR:
+		return (SUN_UCLR_ID);
+	default:
+		return (-1);
+	}
+}
+
+/*
+ * str_to_label -- parse a string into the requested label type.
+ *
+ *	Entry	s = string to parse.
+ *		l = label to create or modify.
+ *		t = label type (MAC_LABEL, USER_CLEAR).
+ *		f = flags
+ *			L_DEFAULT,
+ *			L_MODIFY_EXISTING, use the existing label as a basis for
+ *				the parse string.
+ *			L_NO_CORRECTION, s must be correct and full by the
+ *				label_encoding rules.
+ *
+ *	Exit	l = parsed label value.
+ *		e = index into string of error.
+ *		  = M_BAD_STRING (-1) or could be zero, indicates entire string,
+ *	        e = M_BAD_LABEL (-3), problems with l
+ *
+ *	Returns	 0, success.
+ *		-1, failure
+ *			errno = ENOTSUP, the underlying label mechanism
+ *				does not support label parsing.
+ *				ENOMEM, unable to allocate memory for l.
+ *				EINVAL, invalid argument, l != NULL or
+ *				invalid label type for the underlying
+ *				label mechanism.
+ */
+#define	_M_GOOD_LABEL	-1	/* gfi L_GOOD_LABEL */
+int
+str_to_label(const char *str, m_label_t **l, const m_label_type_t t, uint_t f,
+    int *e)
+{
+	char		*s = (char *)str;
+	char		*p;
+	labeld_data_t	call;
+	labeld_data_t	*callp = &call;
+	size_t		bufsize = sizeof (labeld_data_t);
+	size_t		datasize;
+	int		err;
+	int		id = convert_id(t);
+	boolean_t	new = B_FALSE;
+
+	if (*l == NULL) {
+		if ((*l = m_label_alloc(t)) == NULL) {
+			return (-1);
+		}
+		if (id == -1) {
+			goto badlabel;
+		}
+		_LOW_LABEL(*l, id);
+		new = B_TRUE;
+	} else if (_MTYPE(*l, SUN_INVALID_ID) &&
+	    ((f == L_NO_CORRECTION) || (f == L_DEFAULT))) {
+		_LOW_LABEL(*l, id);
+		new = B_TRUE;
+	} else if (!(_MTYPE(*l, SUN_MAC_ID) || _MTYPE(*l, SUN_CLR_ID))) {
+		goto badlabel;
+	}
+
+	if (new == B_FALSE && id == -1) {
+		goto badlabel;
+	}
+
+	/* get to the beginning of the string to parse */
+	while (isspace(*s)) {
+		s++;
+	}
+
+	/* accept a leading '[' and trailing ']' for old times sake */
+	if (*s == '[') {
+		s++;
+		while (isspace(*s)) {
+			s++;
+		}
+	}
+	p = s;
+	while (*p != '\0' && *p != ']') {
+		p++;
+	}
+
+	/* strip trailing spaces */
+	while (p != s && isspace(*(p-1))) {
+		--p;
+	}
+	*p = '\0';	/* end of string */
+
+	/* translate hex, admin_low and admin_high */
+	id = _MGETTYPE(*l);
+	if (IS_LOW(s)) {
+		_LOW_LABEL(*l, id);
+		return (0);
+	} else if (IS_HIGH(s)) {
+		_HIGH_LABEL(*l, id);
+		return (0);
+	} else if (IS_HEX(f, s)) {
+		int herr;
+
+		herr = htol(s, *l);
+		return (herr);
+	}
+#define	slcall callp->param.acall.cargs.sl_arg
+#define	slret callp->param.aret.rvals.sl_ret
+	/* now try label server */
+
+	datasize = CALL_SIZE(sl_call_t, strlen(str) + 1);
+	if (datasize > bufsize) {
+		if ((callp = malloc(datasize)) == NULL) {
+			return (-1);
+		}
+		bufsize = datasize;
+	}
+	callp->callop = STOL;
+	slcall.label = **l;
+	slcall.flags = f;
+	if (new)
+		slcall.flags |= L_NEW_LABEL;
+	(void) strcpy(slcall.string, str);
+	/*
+	 * callp->reterr = L_GOOD_LABEL (-1) == OK;
+	 *		   L_BAD_CLASSIFICATION (-2) == bad input
+	 *			classification: class
+	 *		   L_BAD_LABEL (-3) == either sring or input label bad
+	 *		   O'E == offset in string 0 == entire string.
+	 */
+	if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) {
+
+		err = callp->reterr;
+		if (callp != &call) {
+			/* free allocated buffer */
+			(void) free(callp);
+		}
+		switch (err) {
+		case _M_GOOD_LABEL:	/* L_GOOD_LABEL */
+			**l = slret.label;
+			return (0);
+		case M_BAD_LABEL:	/* L_BAD_CLASSIFICATION */
+		case M_BAD_STRING:	/* L_BAD_LABEL */
+		default:
+			errno = EINVAL;
+			if (e != NULL)
+				*e = err;
+			return (-1);
+		}
+	}
+	switch (callp->reterr) {
+	case NOSERVER:
+		errno = ENOTSUP;
+		break;
+	default:
+		errno = EINVAL;
+		break;
+	}
+	return (-1);
+
+badlabel:
+	errno = EINVAL;
+	if (e != NULL)
+		*e = M_BAD_LABEL;
+	return (-1);
+}
+#undef	slcall
+#undef	slret
+
+/*
+ * m_label_alloc -- allocate a label structure
+ *
+ *	Entry	t = label type (MAC_LABEL, USER_CLEAR).
+ *
+ *	Exit	If error, NULL, errno set to ENOMEM
+ *		Otherwise, pointer to m_label_t memory
+ */
+
+/* ARGUSED */
+m_label_t *
+m_label_alloc(const m_label_type_t t)
+{
+	m_label_t *l;
+
+	switch (t) {
+	case MAC_LABEL:
+	case USER_CLEAR:
+		if ((l = malloc(sizeof (_mac_label_impl_t))) == NULL) {
+			return (NULL);
+		}
+		_MSETTYPE(l, SUN_INVALID_ID);
+		break;
+	default:
+		errno = EINVAL;
+		return (NULL);
+	}
+	return (l);
+}
+
+/*
+ * m_label_dup -- make a duplicate copy of the given label.
+ *
+ *	Entry	l = label to duplicate.
+ *
+ *	Exit	d = duplicate copy of l.
+ *
+ *	Returns	 0, success
+ *		-1, if error.
+ *			errno = ENOTSUP, the underlying label mechanism
+ *				does not support label duplication.
+ *				ENOMEM, unable to allocate memory for d.
+ *				EINVAL, invalid argument, l == NULL or
+ *				invalid label type for the underlying
+ *				label mechanism.
+ */
+
+int
+m_label_dup(m_label_t **d, const m_label_t *l)
+{
+	if (d == NULL || *d != NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if ((*d = malloc(sizeof (_mac_label_impl_t))) == NULL) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	(void) memcpy(*d, l, sizeof (_mac_label_impl_t));
+	return (0);
+}
+
+/*
+ * m_label_free -- free label structure
+ *
+ *	Entry	l = label to free.
+ *
+ *	Exit	memory freed.
+ *
+ */
+
+void
+m_label_free(m_label_t *l)
+{
+	if (l)
+		free(l);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/common/zone.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include	<stdlib.h>
+#include	<strings.h>
+#include	<zone.h>
+#include	<errno.h>
+#include	<sys/types.h>
+#include 	<sys/tsol/label_macro.h>
+
+/*
+ * Get label from zone name
+ */
+m_label_t *
+getzonelabelbyname(const char *zone)
+{
+	zoneid_t	zoneid;
+
+	if ((zoneid = getzoneidbyname(zone)) == -1) {
+		errno = EINVAL;
+		return (NULL);
+	}
+	return (getzonelabelbyid(zoneid));
+}
+
+/*
+ * Get label from zone id
+ */
+m_label_t *
+getzonelabelbyid(zoneid_t zoneid)
+{
+	m_label_t 	*slabel;
+
+	if ((slabel = m_label_alloc(MAC_LABEL)) == NULL)
+		return (NULL);
+
+	if (zone_getattr(zoneid, ZONE_ATTR_SLBL, slabel,
+	    sizeof (m_label_t)) < 0) {
+		m_label_free(slabel);
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	return (slabel);
+}
+
+/*
+ * Get zone id from label
+ */
+
+zoneid_t
+getzoneidbylabel(const m_label_t *label)
+{
+	m_label_t	admin_low;
+	m_label_t	admin_high;
+	zoneid_t	zoneid;
+	zoneid_t 	*zids;
+	uint_t		nzents;
+	uint_t		nzents_saved;
+	int		i;
+
+	bsllow(&admin_low);
+	bslhigh(&admin_high);
+
+	/* Check for admin_low or admin_high; both are global zone */
+	if (blequal(label, &admin_low) || blequal(label, &admin_high))
+		return (GLOBAL_ZONEID);
+
+	nzents = 0;
+	if (zone_list(NULL, &nzents) != 0)
+		return (-1);
+
+again:
+	if (nzents == 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/*
+	 * Add a small amount of padding here to avoid spinning in a tight loop
+	 * if there's a process running somewhere that's creating lots of zones
+	 * all at once.
+	 */
+	nzents += 8;
+	if ((zids = malloc(nzents * sizeof (zoneid_t))) == NULL)
+		return (-1);
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		free(zids);
+		return (-1);
+	}
+	if (nzents > nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	for (i = 0; i < nzents; i++) {
+		m_label_t	test_sl;
+
+		if (zids[i] == GLOBAL_ZONEID)
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_SLBL, &test_sl,
+		    sizeof (m_label_t)) < 0)
+			continue;	/* Badly configured zone info */
+
+		if (blequal(label, &test_sl) != 0) {
+			zoneid = zids[i];
+			free(zids);
+			return (zoneid);
+		}
+	}
+	free(zids);
+	errno = EINVAL;
+	return (-1);
+}
+
+/*
+ * Get zoneroot for a zoneid
+ */
+
+char *
+getzonerootbyid(zoneid_t zoneid)
+{
+	char zoneroot[MAXPATHLEN];
+
+	if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
+	    sizeof (zoneroot)) == -1) {
+		return (NULL);
+	}
+
+	return (strdup(zoneroot));
+}
+
+/*
+ * Get zoneroot for a zonename
+ */
+
+char *
+getzonerootbyname(const char *zone)
+{
+	zoneid_t	zoneid;
+
+	if ((zoneid = getzoneidbyname(zone)) == -1)
+		return (NULL);
+	return (getzonerootbyid(zoneid));
+}
+
+/*
+ * Get zoneroot for a label
+ */
+
+char *
+getzonerootbylabel(const m_label_t *label)
+{
+	zoneid_t	zoneid;
+
+	if ((zoneid = getzoneidbylabel(label)) == -1)
+		return (NULL);
+	return (getzonerootbyid(zoneid));
+}
+
+/*
+ * Get label of path relative to global zone
+ *
+ * This function must be called from the global zone
+ */
+
+m_label_t *
+getlabelbypath(const char *path)
+{
+	m_label_t	*slabel;
+	zoneid_t 	*zids;
+	uint_t		nzents;
+	uint_t		nzents_saved;
+	int		i;
+
+	if (getzoneid() != GLOBAL_ZONEID) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	nzents = 0;
+	if (zone_list(NULL, &nzents) != 0)
+		return (NULL);
+
+again:
+	/* Add a small amount of padding to avoid loops */
+	nzents += 8;
+	zids = malloc(nzents * sizeof (zoneid_t));
+	if (zids == NULL)
+		return (NULL);
+
+	nzents_saved = nzents;
+
+	if (zone_list(zids, &nzents) != 0) {
+		free(zids);
+		return (NULL);
+	}
+	if (nzents > nzents_saved) {
+		/* list changed, try again */
+		free(zids);
+		goto again;
+	}
+
+	slabel = m_label_alloc(MAC_LABEL);
+	if (slabel == NULL) {
+		free(zids);
+		return (NULL);
+	}
+
+	for (i = 0; i < nzents; i++) {
+		char	zoneroot[MAXPATHLEN];
+		int	zonerootlen;
+
+		if (zids[i] == GLOBAL_ZONEID)
+			continue;
+
+		if (zone_getattr(zids[i], ZONE_ATTR_ROOT, zoneroot,
+		    sizeof (zoneroot)) == -1)
+			continue;	/* Badly configured zone info */
+
+		/*
+		 * Need to handle the case for the /dev directory which is
+		 * parallel to the zone's root directory.  So we back up
+		 * 4 bytes - the strlen of "root".
+		 */
+		if ((zonerootlen = strlen(zoneroot)) <= 4)
+			continue;	/* Badly configured zone info */
+		if (strncmp(path, zoneroot, zonerootlen - 4) == 0) {
+			/*
+			 * If we get a match, the file is in a labeled zone.
+			 * Return the label of that zone.
+			 */
+			if (zone_getattr(zids[i], ZONE_ATTR_SLBL, slabel,
+			    sizeof (m_label_t)) < 0)
+				continue;	/* Badly configured zone info */
+
+			free(zids);
+			return (slabel);
+		}
+	}
+	free(zids);
+	bsllow(slabel);
+	return (slabel);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/i386/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#/
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/sparc/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/sparcv9/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include $(SRC)/lib/Makefile.spec.arch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/Makefile.targ	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+LIBRARY = libtsol.a
+VERS    = .2
+OBJECTS =	obsolete.o	\
+		private.o	\
+		tsol.o
+SPECCPP = -I../../common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/amd64/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/i386/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/obsolete.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,122 @@
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	Obsolete interfaces to be removed from a future release.
+#	Retained to aid 3rd party initial porting from TS8.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+function	bcleartoh_r
+include		<tsol/label.h>
+declaration	char *bcleartoh_r(const bclear_t *clearance, char *hex);
+version		SUNWprivate_1.1
+end
+
+function	bcleartoh
+include		<tsol/label.h>
+declaration	char *bcleartoh(const bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	bltocolor
+include		<tsol/label.h>
+declaration	char *bltocolor(const blevel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	bltocolor_r
+include		<tsol/label.h>
+declaration	char *bltocolor_r(const blevel_t *label, int size, \
+		    char *color_name);
+version		SUNWprivate_1.1
+end
+
+function	bsltoh
+include		<tsol/label.h>
+declaration	char *bsltoh(const bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	bsltoh_r
+include		<tsol/label.h>
+declaration	char *bsltoh_r(const bslabel_t *label, char *hex);
+version		SUNWprivate_1.1
+end
+
+function	bsltos
+include		<tsol/label.h>
+declaration	ssize_t bsltos(const bslabel_t *label, char **string, \
+		    size_t str_len, int flags);
+version		SUNWprivate_1.1
+end
+
+function	h_alloc
+include		<tsol/label.h>
+declaration	char *h_alloc(unsigned char id);
+version		SUNWprivate_1.1
+end
+
+function	h_free
+include		<tsol/label.h>
+declaration	void h_free(char *hex);
+version		SUNWprivate_1.1
+end
+
+function	htobclear
+include		<tsol/label.h>
+declaration	int htobclear(const char *s, bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	htobsl
+include		<tsol/label.h>
+declaration	int htobsl(const char *s, bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	sbcleartos
+include		<tsol/label.h>
+declaration	char *sbcleartos(const bclear_t *clearance, int len);
+version		SUNWprivate_1.1
+end
+
+function	sbsltos
+include		<tsol/label.h>
+declaration	char *sbsltos(const bslabel_t *label, int len);
+version		SUNWprivate_1.1
+end
+
+function	stobclear
+include		<tsol/label.h>
+declaration	int stobclear(const char *string, bclear_t *clearance, \
+		    int flags, int *error);
+version		SUNWprivate_1.1
+end
+
+function	stobsl
+include		<tsol/label.h>
+declaration	int stobsl(const char *string, bslabel_t *label, int flags, \
+		    int *error);
+version		SUNWprivate_1.1
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/private.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,239 @@
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	Project Private to the Trusted eXtensions project.
+#	Not for public consumption or to be documented.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+function	bclearhigh
+include		<tsol/label.h>
+declaration	void bclearhigh(bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	bclearlow
+include		<tsol/label.h>
+declaration	void bclearlow(bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	bcleartos
+include		<tsol/label.h>
+declaration	ssize_t bcleartos(const bclear_t *clearance, char **string, \
+		    size_t str_len, int flags);
+version		SUNWprivate_1.1
+end
+
+function	bclearundef
+include		<tsol/label.h>
+declaration	void bclearundef(bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	bclearvalid
+include		<tsol/label.h>
+declaration	int bclearvalid(const bclear_t *clearance);
+version		SUNWprivate_1.1
+end
+
+function	bclearcvtfull
+include		<tsol/label.h>
+declaration	int bclearcvtfull(const bclear_t *clearance, \
+		    const blrange_t *bounds, int flags, char **string, \
+		    char **long_words[], char **short_words[], \
+		    char *display[], int *first_compartment, \
+		    int *display_size);
+version		SUNWprivate_1.1
+end
+
+function	bclearcvt
+include		<tsol/label.h>
+declaration	int bclearcvt(const bclear_t *clearance, int flags, \
+		    char **string, char *display[]);
+version		SUNWprivate_1.1
+end
+
+function	blinrange
+include		<tsol/label.h>
+declaration	int blinrange(const blevel_t *label, const blrange_t *range);
+version		SUNWprivate_1.1
+end
+
+function	blinset
+include		<tsol/label.h>
+declaration	int blinset(const bslabel_t *label, const set_id *id);
+version		SUNWprivate_1.1
+end
+
+function	blmaximum
+include		<tsol/label.h>
+declaration	void blmaximum(blevel_t *label1, const blevel_t *label2);
+version		SUNWprivate_1.1
+end
+
+function	blminimum
+include		<tsol/label.h>
+declaration	void blminimum(blevel_t *label1, const blevel_t *label2);
+version		SUNWprivate_1.1
+end
+
+function	bltype
+include		<tsol/label.h>
+declaration	int bltype(const void *label, uint8_t type);
+version		SUNWprivate_1.1
+end
+
+function	bslcvtfull
+include		<tsol/label.h>
+declaration	int bslcvtfull(const bslabel_t *label,
+		    const blrange_t *bounds, \
+		    int flags, char **string, char **long_words[], \
+		    char **short_words[], char *display[], \
+		    int *first_compartment, int *display_size);
+version		SUNWprivate_1.1
+end
+
+function	bslcvt
+include		<tsol/label.h>
+declaration	int bslcvt(const bslabel_t *label, int flags, char **string, \
+		    char *display[]);
+version		SUNWprivate_1.1
+end
+
+function	bslhigh
+include		<tsol/label.h>
+declaration	void bslhigh(bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	bsllow
+include		<tsol/label.h>
+declaration	void bsllow(bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	bslundef
+include		<tsol/label.h>
+declaration	void bslundef(bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	bslvalid
+include		<tsol/label.h>
+declaration	int bslvalid(const bslabel_t *label);
+version		SUNWprivate_1.1
+end
+
+function	labelinfo
+include		<tsol/label.h>
+declaration	int labelinfo(struct label_info *info);
+version		SUNWprivate_1.1
+end
+
+function	labelfields
+include		<tsol/label.h>
+declaration	int labelfields(struct name_fields *fields);
+version		SUNWprivate_1.1
+end
+
+function	labelvers
+include		<tsol/label.h>
+declaration	ssize_t labelvers(char **version, int len);
+version		SUNWprivate_1.1
+end
+
+function	getpathbylabel
+include		<tsol/label.h>
+declaration	char *getpathbylabel(const char *path_name, \
+		    char *resolved_path, size_t bufsize, const bslabel_t *sl);
+version		SUNWprivate_1.1
+end
+
+function	getlabelbypath
+include		<tsol/label.h>
+declaration	m_label_t *getlabelbypath(char *path);
+version		SUNWprivate_1.1
+end
+
+function	blabel_alloc
+include		<tsol/label.h>
+declaration	blevel_t *blabel_alloc(void);
+version		SUNWprivate_1.1
+end
+
+function	blabel_free
+include		<tsol/label.h>
+declaration	void blabel_free(blevel_t *label_p);
+version		SUNWprivate_1.1
+end
+
+function	blabel_size
+include		<tsol/label.h>
+declaration	size_t blabel_size(void);
+version		SUNWprivate_1.1
+end
+
+function	setbltype
+include		<tsol/label.h>
+declaration	void setbltype(void *label, uint8_t type);
+version		SUNWprivate_1.1
+end
+
+function	bisinvalid
+include		<tsol/label.h>
+declaration	boolean_t bisinvalid(const void *label);
+version		SUNWprivate_1.1
+end
+
+function	set_effective_priv
+include		<tsol/label.h>
+declaration	int set_effective_priv(priv_op_t op, int num_priv, ...);
+version		SUNWprivate_1.1
+end
+
+function	set_inheritable_priv
+include		<tsol/label.h>
+declaration	int set_inheritable_priv(priv_op_t op, int num_priv, ...);
+version		SUNWprivate_1.1
+end
+
+function	set_permitted_priv
+include		<tsol/label.h>
+declaration	int set_permitted_priv(priv_op_t op, int num_priv, ...);
+version		SUNWprivate_1.1
+end
+
+function	userdefs
+include		<tsol/label.h>
+declaration	int userdefs(bslabel_t *sl, bclear_t *clear);
+version		SUNWprivate_1.1
+end
+
+function	zonecopy
+include		<tsol/label.h>
+declaration	int zonecopy(bslabel_t *src_win_sl, char *remote_dir, \
+		    char *filename, char *local_dir, int transfer_mode);
+version		SUNWprivate_1.1
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/sparc/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/sparcv9/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/tsol.spec	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,143 @@
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+function	label_to_str
+include		<tsol/label.h>
+declaration	int label_to_str(const m_label_t *label, char **string, \
+			const m_label_str_t conversion_type, uint_t flags);
+version		SUNW_2.1
+end
+
+function	m_label_alloc
+include		<tsol/label.h>
+declaration	m_label_t m_label_dup(const m_label_type_t *type);
+version		SUNW_2.1
+end
+
+function	m_label_dup
+include		<tsol/label.h>
+declaration	int m_label_dup(m_label_t **dst, const m_label_t *src);
+version		SUNW_2.1
+end
+
+function	m_label_free
+include		<tsol/label.h>
+declaration	void m_label_free(m_label_t *label);
+version		SUNW_2.1
+end
+
+function	str_to_label
+include		<tsol/label.h>
+declaration	int str_to_label(const char *str, m_label_t **label, \
+			const m_label_type_t type, unit_t flags, int *error);
+version		SUNW_2.1
+end
+
+function	bldominates
+include		<tsol/label.h>
+declaration	int bldominates(const m_label_t *label1, \
+		    const m_label_t *label2);
+version		SUNW_2.1
+end
+
+function	blequal
+include		<tsol/label.h>
+declaration	int blequal(const m_label_t *label1, const m_label_t *label2);
+version		SUNW_2.1
+end
+
+function	blstrictdom
+include		<tsol/label.h>
+declaration	int blstrictdom(const m_label_t *label1, \
+		    const m_label_t *label2);
+version		SUNW_2.1
+end
+
+function	getlabel
+include		<tsol/label.h>
+declaration	int getlabel(const char *path, m_label_t *label);
+version		SUNW_2.1
+end
+
+function	fgetlabel
+include		<tsol/label.h>
+declaration	int fgetlabel(int fd, m_label_t *label);
+version		SUNW_2.1
+end
+
+function	getplabel
+include		<tsol/label.h>
+declaration	int getplabel(m_label_t *label_p);
+version		SUNW_2.1
+end
+
+function	getzoneidbylabel
+include		<tsol/label.h>
+declaration	zoneid_t getzoneidbylabel(const m_label_t *label);
+version		SUNW_2.1
+end
+
+function	getzonelabelbyid
+include		<tsol/label.h>
+declaration	m_label_t *getzonelabelbyid(zoneid_t zoneid);
+version		SUNW_2.1
+end
+
+function	getzonelabelbyname
+include		<tsol/label.h>
+declaration	m_label_t *getzonelabelbyname(char *zone);
+version		SUNW_2.1
+end
+
+function	getzonerootbyid
+include		<tsol/label.h>
+declaration	char *getzonerootbyid(zoneid_t zoneid);
+version		SUNW_2.1
+end
+
+function	getzonerootbylabel
+include		<tsol/label.h>
+declaration	char *getzonerootbylabel(m_label_t *label);
+version		SUNW_2.1
+end
+
+function	getzonerootbyname
+include		<tsol/label.h>
+declaration	char *getzonerootbyname(char *zone);
+version		SUNW_2.1
+end
+
+function	setflabel
+include		<tsol/label.h>
+declaration	int setflabel(const char *path, m_label_t *label);
+version		SUNW_2.1
+end
+
+function	getuserrange
+include		<tsol/label.h>
+declaration	m_range_t *getuserrange(const char *username);
+version		SUNW_2.1
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtsol/spec/versions	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# vers file for libtsol
+#
+
+sparc {
+	SUNW_2.1;
+	SUNWprivate_1.1;
+}
+i386 {
+	SUNW_2.1;
+	SUNWprivate_1.1;
+}
+sparcv9 {
+	SUNW_2.1;
+	SUNWprivate_1.1;
+}
+amd64 {
+	SUNW_2.1;
+	SUNWprivate_1.1;
+}
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c	Fri Mar 24 12:29:20 2006 -0800
@@ -49,8 +49,6 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
-#include <priv.h>
-
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
 
@@ -125,8 +123,8 @@
 #define	ATTACH_FORCED	"SUNWattached.xml"
 #define	PKG_PATH	"/var/sadm/pkg"
 #define	CONTENTS_FILE	"/var/sadm/install/contents"
-#define	ALL_ZONES	"SUNW_PKG_ALLZONES=true\n"
-#define	THIS_ZONE	"SUNW_PKG_THISZONE=true\n"
+#define	SUNW_PKG_ALL_ZONES	"SUNW_PKG_ALLZONES=true\n"
+#define	SUNW_PKG_THIS_ZONE	"SUNW_PKG_THISZONE=true\n"
 #define	VERSION		"VERSION="
 #define	PATCHLIST	"PATCHLIST="
 #define	PATCHINFO	"PATCH_INFO_"
@@ -3417,7 +3415,9 @@
 	PRIV_IPC_DAC_READ,
 	PRIV_IPC_DAC_WRITE,
 	PRIV_IPC_OWNER,
+	PRIV_NET_BINDMLP,
 	PRIV_NET_ICMPACCESS,
+	PRIV_NET_MAC_AWARE,
 	PRIV_NET_PRIVADDR,
 	PRIV_PROC_CHROOT,
 	PRIV_SYS_AUDIT,
@@ -5294,10 +5294,10 @@
 			len = strlen(infop->zpi_version);
 			*(infop->zpi_version + len - 1) = 0;
 
-		} else if (strcmp(buf, ALL_ZONES) == 0) {
+		} else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) {
 			infop->zpi_all_zones = B_TRUE;
 
-		} else if (strcmp(buf, THIS_ZONE) == 0) {
+		} else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) {
 			infop->zpi_this_zone = B_TRUE;
 
 		} else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1)
--- a/usr/src/lib/nsswitch/files/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/files/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -49,7 +50,9 @@
 		getexecattr.o		\
 		getuserattr.o		\
 		getauuser.o		\
-		netmasks.o
+		netmasks.o		\
+		tsol_getrhent.o		\
+		tsol_gettpent.o
 
 # include common nsswitch library definitions.
 include		../../Makefile.com
--- a/usr/src/lib/nsswitch/files/common/mapfile-vers	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/files/common/mapfile-vers	Fri Mar 24 12:29:20 2006 -0800
@@ -1,15 +1,14 @@
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -59,6 +58,8 @@
 		_nss_files_services_constr;
 		_nss_files_shadow_constr;
 		_nss_files_user_attr_constr;
+		_nss_files_tnrhdb_constr;
+		_nss_files_tnrhtp_constr;
 	local:
 		*;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/nsswitch/files/common/tsol_getrhent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,73 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "files_common.h"
+#include <string.h>
+#include <libtsnet.h>
+
+/*
+ *	files/tsol_getrhent.c --
+ *           "files" backend for nsswitch "tnrhdb" database
+ */
+static int
+check_addr(nss_XbyY_args_t *args)
+{
+	tsol_rhstr_t *rhstrp = (tsol_rhstr_t *)args->returnval;
+
+	if ((args->key.hostaddr.type == rhstrp->family) &&
+	    (strcmp(args->key.hostaddr.addr, rhstrp->address) == 0))
+		return (1);
+
+	return (0);
+}
+
+static nss_status_t
+getbyaddr(files_backend_ptr_t be, void *a)
+{
+	nss_XbyY_args_t *argp = a;
+
+	return (_nss_files_XY_all(be, argp, 1,
+		argp->key.hostaddr.addr, check_addr));
+}
+
+static files_backend_op_t tsol_rh_ops[] = {
+	_nss_files_destr,
+	_nss_files_endent,
+	_nss_files_setent,
+	_nss_files_getent_netdb,
+	getbyaddr
+};
+
+/* ARGSUSED */
+nss_backend_t *
+_nss_files_tnrhdb_constr(const char *dummy1, const char *dummy2,
+    const char *dummy3)
+{
+	return (_nss_files_constr(tsol_rh_ops,
+	    sizeof (tsol_rh_ops) / sizeof (tsol_rh_ops[0]), TNRHDB_PATH,
+	    NSS_LINELEN_TSOL_RH, NULL));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/nsswitch/files/common/tsol_gettpent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "files_common.h"
+#include <sys/tsol/tndb.h>
+#include <string.h>
+
+/*
+ *	files/tsol_gettpent.c --
+ *           "files" backend for nsswitch "tnrhtp" database
+ */
+static int
+check_name(nss_XbyY_args_t *args)
+{
+	tsol_tpstr_t	*tpstrp	= (tsol_tpstr_t *)args->returnval;
+	const char	*name	= args->key.name;
+
+	if (strcmp(tpstrp->template, name) == 0)
+		return (1);
+
+	return (0);
+}
+
+static nss_status_t
+getbyname(be, a)
+	files_backend_ptr_t	be;
+	void			*a;
+{
+	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
+
+	return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name));
+}
+
+static files_backend_op_t tsol_tp_ops[] = {
+	_nss_files_destr,
+	_nss_files_endent,
+	_nss_files_setent,
+	_nss_files_getent_netdb,
+	getbyname
+};
+
+nss_backend_t *
+_nss_files_tnrhtp_constr(dummy1, dummy2, dummy3)
+	const char	*dummy1, *dummy2, *dummy3;
+{
+	return (_nss_files_constr(tsol_tp_ops,
+				sizeof (tsol_tp_ops) / sizeof (tsol_tp_ops[0]),
+				"/etc/security/tsol/tnrhtp",
+				NSS_LINELEN_TSOL_TP,
+				NULL));
+}
--- a/usr/src/lib/nsswitch/ldap/Makefile.com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/ldap/Makefile.com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,12 +17,14 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright (c) 1999-2001 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
 #
 # lib/nsswitch/ldap/Makefile.com
 
@@ -51,6 +52,8 @@
 		getservent.o	\
 		getspent.o	\
 		getuserattr.o	\
+		tsol_getrhent.o	\
+		tsol_gettpent.o	\
 		ldap_common.o	\
 		ldap_utils.o
 
--- a/usr/src/lib/nsswitch/ldap/common/ldap_common.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,6 +54,9 @@
 #define	_F_GETSPENT		"(objectclass=shadowAccount)"
 #define	_F_GETUSERNAME		"(objectClass=SolarisUserAttr)"
 #define	_F_GETPROJENT		"(objectClass=SolarisProject)"
+#define	_F_GETTNRHDB		"(objectClass=ipTnetHost)"
+#define	_F_GETTNRHTP		"(&(objectClass=ipTnetTemplate)"\
+				"(SolarisAttrKeyValue=*))"
 #define	_F_GETENT_SSD		"(%s)"
 
 static struct gettablefilter {
@@ -77,6 +79,8 @@
 	{(char *)_USERATTR,	(char *)_F_GETUSERNAME},
 	{(char *)_PROJECT,	(char *)_F_GETPROJENT},
 	{(char *)_PRINTERS,	(char *)_F_GETPRINTERENT},
+	{(char *)_TNRHDB,	(char *)_F_GETTNRHDB},
+	{(char *)_TNRHTP,	(char *)_F_GETTNRHTP},
 	{(char *)NULL,		(char *)NULL}
 };
 
--- a/usr/src/lib/nsswitch/ldap/common/ldap_common.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -68,6 +67,8 @@
 #define	_SERVICES		"services"
 #define	_SHADOW			"shadow"
 #define	_USERATTR		"user_attr"
+#define	_TNRHDB			"tnrhdb"
+#define	_TNRHTP			"tnrhtp"
 
 #define	NSS_STR_PARSE_NO_ADDR	(NSS_STR_PARSE_ERANGE + 100)
 
--- a/usr/src/lib/nsswitch/ldap/common/mapfile-vers	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/lib/nsswitch/ldap/common/mapfile-vers	Fri Mar 24 12:29:20 2006 -0800
@@ -1,15 +1,14 @@
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -61,6 +60,8 @@
 		_nss_ldap_shadow_constr;
 		_nss_ldap_publickey_constr;
 		_nss_ldap_user_attr_constr;
+		_nss_ldap_tnrhdb_constr;
+		_nss_ldap_tnrhtp_constr;
 	local:
 		*;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <netdb.h>
+#include "ldap_common.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/tsol/tndb.h>
+
+/* tnrhdb attributes filters */
+#define	_TNRHDB_ADDR		"ipTnetNumber"
+#define	_TNRHDB_TNAME		"ipTnetTemplateName"
+#define	_F_GETTNDBBYADDR	"(&(objectClass=ipTnetHost)(ipTnetNumber=%s))"
+#define	_F_GETTNDBBYADDR_SSD	"(&(%%s)(ipTnetNumber=%s))"
+
+static const char *tnrhdb_attrs[] = {
+	_TNRHDB_ADDR,
+	_TNRHDB_TNAME,
+	NULL
+};
+
+static int
+_nss_ldap_tnrhdb2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
+{
+	int			i, nss_result;
+	int			len = 0;
+	int			buflen = 0;
+	char			*buffer = NULL;
+	char			*ceiling = NULL;
+	ns_ldap_attr_t		*attrptr;
+	ns_ldap_result_t	*result = be->result;
+	tsol_rhstr_t		*rhstrp;
+
+	buffer = argp->buf.buffer;
+	buflen = argp->buf.buflen;
+	if (argp->buf.result == NULL) {
+		nss_result = NSS_STR_PARSE_ERANGE;
+		goto result_tnrhdb2ent;
+	}
+	rhstrp = (tsol_rhstr_t *)(argp->buf.result);
+	rhstrp->family = 0;
+	rhstrp->address = rhstrp->template = NULL;
+	ceiling = buffer + buflen;
+	(void) memset(argp->buf.buffer, 0, buflen);
+	attrptr = getattr(result, 0);
+	if (attrptr == NULL) {
+		nss_result = NSS_STR_PARSE_PARSE;
+		goto result_tnrhdb2ent;
+	}
+	for (i = 0; i < result->entry->attr_count; i++) {
+		attrptr = getattr(result, i);
+		if (attrptr == NULL) {
+			nss_result = NSS_STR_PARSE_PARSE;
+			goto result_tnrhdb2ent;
+		}
+		if (strcasecmp(attrptr->attrname, _TNRHDB_ADDR) == 0) {
+			len = strlen(attrptr->attrvalue[0]);
+			if (len < 1 || (attrptr->attrvalue[0] == '\0')) {
+				nss_result = NSS_STR_PARSE_PARSE;
+				goto result_tnrhdb2ent;
+			}
+			rhstrp->address = buffer;
+			buffer += len + 1;
+			if (buffer >= ceiling) {
+				nss_result = (int)NSS_STR_PARSE_ERANGE;
+				goto result_tnrhdb2ent;
+			}
+			(void) strcpy(rhstrp->address, attrptr->attrvalue[0]);
+			continue;
+		}
+		if (strcasecmp(attrptr->attrname, _TNRHDB_TNAME) == 0) {
+			len = strlen(attrptr->attrvalue[0]);
+			if (len < 1 || (attrptr->attrvalue[0] == '\0')) {
+				nss_result = NSS_STR_PARSE_PARSE;
+				goto result_tnrhdb2ent;
+			}
+			rhstrp->template = buffer;
+			buffer += len + 1;
+			if (buffer >= ceiling) {
+				nss_result = (int)NSS_STR_PARSE_ERANGE;
+				goto result_tnrhdb2ent;
+			}
+			(void) strcpy(rhstrp->template, attrptr->attrvalue[0]);
+			continue;
+		}
+	}
+	nss_result = NSS_STR_PARSE_SUCCESS;
+
+#ifdef	DEBUG
+	(void) printf("\n[tsol_getrhent.c: _nss_ldap_tnrhdb2ent]\n");
+	(void) printf("      address: [%s]\n",
+	    rhstrp->address ? rhstrp->address : "NULL");
+	(void) printf("template: [%s]\n",
+	    rhstrp->template ? rhstrp->template : "NULL");
+#endif	/* DEBUG */
+
+result_tnrhdb2ent:
+	(void) __ns_ldap_freeResult(&be->result);
+	return (nss_result);
+}
+
+
+static nss_status_t
+getbyaddr(ldap_backend_ptr be, void *a)
+{
+	char		searchfilter[SEARCHFILTERLEN];
+	char		userdata[SEARCHFILTERLEN];
+	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
+	struct in_addr  addr;
+	char 		buf[18];
+	extern char	*inet_ntoa_r();
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "\n[tsol_getrhent.c: getbyaddr]\n");
+#endif	/* DEBUG */
+
+	(void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr));
+	(void) inet_ntoa_r(addr, buf);
+
+	if (snprintf(searchfilter, sizeof (searchfilter), _F_GETTNDBBYADDR,
+	    buf) < 0)
+		return ((nss_status_t)NSS_NOTFOUND);
+
+	if (snprintf(userdata, sizeof (userdata), _F_GETTNDBBYADDR_SSD,
+	    buf) < 0)
+		return ((nss_status_t)NSS_NOTFOUND);
+
+	return (_nss_ldap_lookup(be, argp, _TNRHDB, searchfilter, NULL,
+	    _merge_SSD_filter, userdata));
+}
+
+
+static ldap_backend_op_t tnrhdb_ops[] = {
+	_nss_ldap_destr,
+	_nss_ldap_endent,
+	_nss_ldap_setent,
+	_nss_ldap_getent,
+	getbyaddr
+};
+
+
+/* ARGSUSED */
+nss_backend_t *
+_nss_ldap_tnrhdb_constr(const char *dummy1,
+    const char *dummy2,
+    const char *dummy3,
+    const char *dummy4,
+    const char *dummy5)
+{
+#ifdef	DEBUG
+	(void) fprintf(stdout,
+	    "\n[tsol_getrhent.c: _nss_ldap_tnrhdb_constr]\n");
+#endif
+	return ((nss_backend_t *)_nss_ldap_constr(tnrhdb_ops,
+		sizeof (tnrhdb_ops)/sizeof (tnrhdb_ops[0]), _TNRHDB,
+		tnrhdb_attrs, _nss_ldap_tnrhdb2ent));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,182 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "ldap_common.h"
+#include <sys/tsol/tndb.h>
+
+/* tnrhtp attributes filters */
+#define	_TNRHTP_NAME		"ipTnetTemplateName"
+#define	_TNRHTP_ATTRS		"SolarisAttrKeyValue"
+#define	_F_GETTNTPBYNAME	"(&(objectClass=ipTnetTemplate)"\
+				"(ipTnetTemplateName=%s))"
+#define	_F_GETTNTPBYNAME_SSD	"(&(%%s)(ipTnetTemplateName=%s))"
+
+static const char *tnrhtp_attrs[] = {
+	_TNRHTP_NAME,
+	_TNRHTP_ATTRS,
+	NULL
+};
+
+static int
+_nss_ldap_tnrhtp2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
+{
+	int			i, nss_result;
+	int			len = 0;
+	int			buflen = 0;
+	char			*buffer = NULL;
+	char			*ceiling = NULL;
+	ns_ldap_attr_t		*attrptr;
+	ns_ldap_result_t	*result = be->result;
+	tsol_tpstr_t		*tpstrp;
+
+	buffer = argp->buf.buffer;
+	buflen = argp->buf.buflen;
+	if (argp->buf.result == NULL) {
+		nss_result = (int)NSS_STR_PARSE_ERANGE;
+		goto result_tnrhtp2ent;
+	}
+	tpstrp = (tsol_tpstr_t *)(argp->buf.result);
+	tpstrp->template = tpstrp->attrs = NULL;
+	ceiling = buffer + buflen;
+	(void) memset(argp->buf.buffer, 0, buflen);
+	attrptr = getattr(result, 0);
+	if (attrptr == NULL) {
+		nss_result = NSS_STR_PARSE_PARSE;
+		goto result_tnrhtp2ent;
+	}
+	for (i = 0; i < result->entry->attr_count; i++) {
+		attrptr = getattr(result, i);
+		if (attrptr == NULL) {
+			nss_result = (int)NSS_STR_PARSE_PARSE;
+			goto result_tnrhtp2ent;
+		}
+#ifdef	DEBUG
+		(void) fprintf(stdout,
+		    "\n[tsol_gettpent.c: _nss_ldap_tnrhtp2ent %d]\n", i);
+		(void) fprintf(stdout, "      entry value count %d: %s:%s\n",
+		    attrptr->value_count,
+		    attrptr->attrname ? attrptr->attrname : "NULL",
+		    attrptr->attrvalue[0] ? attrptr->attrvalue[0] : "NULL");
+#endif	/* DEBUG */
+		if (strcasecmp(attrptr->attrname, _TNRHTP_NAME) == 0) {
+			len = strlen(attrptr->attrvalue[0]);
+			if (len < 1 || (attrptr->attrvalue[0] == '\0')) {
+				nss_result = (int)NSS_STR_PARSE_PARSE;
+				goto result_tnrhtp2ent;
+			}
+			tpstrp->template = buffer;
+			buffer += len + 1;
+			if (buffer >= ceiling) {
+				nss_result = (int)NSS_STR_PARSE_ERANGE;
+				goto result_tnrhtp2ent;
+			}
+			(void) strcpy(tpstrp->template, attrptr->attrvalue[0]);
+			continue;
+		}
+		if (strcasecmp(attrptr->attrname, _TNRHTP_ATTRS) == 0) {
+			len = strlen(attrptr->attrvalue[0]);
+			if (len < 1 || (attrptr->attrvalue[0] == '\0')) {
+				nss_result = (int)NSS_STR_PARSE_PARSE;
+				goto result_tnrhtp2ent;
+			}
+			tpstrp->attrs = buffer;
+			buffer += len + 1;
+			if (buffer >= ceiling) {
+				nss_result = (int)NSS_STR_PARSE_PARSE;
+				goto result_tnrhtp2ent;
+			}
+			(void) strcpy(tpstrp->attrs, attrptr->attrvalue[0]);
+			continue;
+		}
+	}
+	if (tpstrp->attrs == NULL)
+		nss_result = NSS_STR_PARSE_PARSE;
+	else
+		nss_result = NSS_STR_PARSE_SUCCESS;
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "\n[tsol_gettpent.c: _nss_ldap_tnrhtp2ent]\n");
+	(void) fprintf(stdout, "      template: [%s]\n",
+	    tpstrp->template ? tpstrp->template : "NULL");
+	(void) fprintf(stdout, "      attrs: [%s]\n",
+	    tpstrp->attrs ? tpstrp->attrs : "NULL");
+#endif	/* DEBUG */
+
+result_tnrhtp2ent:
+	(void) __ns_ldap_freeResult(&be->result);
+	return (nss_result);
+}
+
+
+static nss_status_t
+getbyname(ldap_backend_ptr be, void *a)
+{
+	char		searchfilter[SEARCHFILTERLEN];
+	char		userdata[SEARCHFILTERLEN];
+	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
+
+#ifdef	DEBUG
+	(void) fprintf(stdout, "\n[tsol_gettpent.c: getbyname]\n");
+#endif	/* DEBUG */
+
+	if (snprintf(searchfilter, SEARCHFILTERLEN, _F_GETTNTPBYNAME,
+	    argp->key.name) < 0)
+		return ((nss_status_t)NSS_NOTFOUND);
+
+	if (snprintf(userdata, sizeof (userdata), _F_GETTNTPBYNAME_SSD,
+	    argp->key.name) < 0)
+		return ((nss_status_t)NSS_NOTFOUND);
+
+	return (_nss_ldap_lookup(be, argp, _TNRHTP, searchfilter, NULL,
+	    _merge_SSD_filter, userdata));
+}
+
+
+static ldap_backend_op_t tnrhtp_ops[] = {
+	_nss_ldap_destr,
+	_nss_ldap_endent,
+	_nss_ldap_setent,
+	_nss_ldap_getent,
+	getbyname
+};
+
+
+nss_backend_t *
+_nss_ldap_tnrhtp_constr(const char *dummy1,
+    const char *dummy2,
+    const char *dummy3,
+    const char *dummy4,
+    const char *dummy5)
+{
+#ifdef	DEBUG
+	(void) fprintf(stdout,
+	    "\n[gettnrhtpattr.c: _nss_ldap_tnrhtp_constr]\n");
+#endif
+	return ((nss_backend_t *)_nss_ldap_constr(tnrhtp_ops,
+		sizeof (tnrhtp_ops)/sizeof (tnrhtp_ops[0]), _TNRHTP,
+		tnrhtp_attrs, _nss_ldap_tnrhtp2ent));
+}
--- a/usr/src/pkgdefs/SUNWarc/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -182,6 +183,8 @@
 f none usr/lib/llib-lssasnmp.ln 644 root bin
 s none usr/lib/llib-lsysevent=../../lib/llib-lsysevent
 s none usr/lib/llib-lsysevent.ln=../../lib/llib-lsysevent.ln
+s none usr/lib/llib-ltsnet.ln=../../lib/llib-ltsnet.ln
+s none usr/lib/llib-ltsol.ln=../../lib/llib-ltsol.ln
 s none usr/lib/llib-lumem=../../lib/llib-lumem
 s none usr/lib/llib-lumem.ln=../../lib/llib-lumem.ln
 s none usr/lib/llib-luuid=../../lib/llib-luuid
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -137,6 +138,8 @@
 s none usr/lib/amd64/llib-ltermlib.ln=../../../lib/amd64/llib-lcurses.ln
 s none usr/lib/amd64/llib-lthread.ln=../../../lib/amd64/llib-lthread.ln
 s none usr/lib/amd64/llib-lthread_db.ln=../../../lib/amd64/llib-lc_db.ln
+s none usr/lib/amd64/llib-ltsnet.ln=../../../lib/amd64/llib-ltsnet.ln
+s none usr/lib/amd64/llib-ltsol.ln=../../../lib/amd64/llib-ltsol.ln
 s none usr/lib/amd64/llib-lumem.ln=../../../lib/amd64/llib-lumem.ln
 s none usr/lib/amd64/llib-luuid.ln=../../../lib/amd64/llib-luuid.ln
 f none usr/lib/amd64/llib-lvolmgt.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -132,6 +133,8 @@
 s none usr/lib/sparcv9/llib-ltermlib.ln=../../../lib/sparcv9/llib-lcurses.ln
 s none usr/lib/sparcv9/llib-lthread.ln=../../../lib/sparcv9/llib-lthread.ln
 s none usr/lib/sparcv9/llib-lthread_db.ln=../../../lib/sparcv9/llib-lc_db.ln
+s none usr/lib/sparcv9/llib-ltsnet.ln=../../../lib/sparcv9/llib-ltsnet.ln
+s none usr/lib/sparcv9/llib-ltsol.ln=../../../lib/sparcv9/llib-ltsol.ln
 s none usr/lib/sparcv9/llib-lumem.ln=../../../lib/sparcv9/llib-lumem.ln
 s none usr/lib/sparcv9/llib-luuid.ln=../../../lib/sparcv9/llib-luuid.ln
 f none usr/lib/sparcv9/llib-lvolmgt.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarcr/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarcr/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -121,6 +122,10 @@
 s none lib/llib-ltermlib=./llib-lcurses
 f none lib/llib-lthread 644 root bin
 f none lib/llib-lthread.ln 644 root bin
+f none lib/llib-ltsnet 644 root bin
+f none lib/llib-ltsnet.ln 644 root bin
+f none lib/llib-ltsol 644 root bin
+f none lib/llib-ltsol.ln 644 root bin
 f none lib/llib-lumem 0644 root bin
 f none lib/llib-lumem.ln 0644 root bin
 f none lib/llib-luuid 644 root bin
--- a/usr/src/pkgdefs/SUNWarcr/prototype_i386	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarcr/prototype_i386	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -90,6 +91,8 @@
 s none lib/amd64/llib-ltermlib.ln=./llib-lcurses.ln
 s none lib/amd64/llib-ltermlib=./llib-lcurses
 f none lib/amd64/llib-lthread.ln 644 root bin
+f none lib/amd64/llib-ltsnet.ln 644 root bin
+f none lib/amd64/llib-ltsol.ln 644 root bin
 f none lib/amd64/llib-lumem.ln 644 root bin
 f none lib/amd64/llib-luuid.ln 644 root bin
 f none lib/amd64/llib-luutil.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarcr/prototype_sparc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWarcr/prototype_sparc	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -18,9 +17,11 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -90,6 +91,8 @@
 s none lib/sparcv9/llib-ltermlib.ln=./llib-lcurses.ln
 s none lib/sparcv9/llib-ltermlib=./llib-lcurses
 f none lib/sparcv9/llib-lthread.ln 644 root bin
+f none lib/sparcv9/llib-ltsnet.ln 644 root bin
+f none lib/sparcv9/llib-ltsol.ln 644 root bin
 f none lib/sparcv9/llib-lumem.ln 0644 root bin
 f none lib/sparcv9/llib-luuid.ln 644 root bin
 f none lib/sparcv9/llib-lxnet.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -245,6 +247,10 @@
 s none usr/lib/libthread.so.1=../../lib/libthread.so.1
 s none usr/lib/libthread_db.so=../../lib/libc_db.so.1
 s none usr/lib/libthread_db.so.1=../../lib/libc_db.so.1
+s none usr/lib/libtsnet.so.1=../../lib/libtsnet.so.1
+s none usr/lib/libtsnet.so=../../lib/libtsnet.so.1
+s none usr/lib/libtsol.so.2=../../lib/libtsol.so.2
+s none usr/lib/libtsol.so=../../lib/libtsol.so.2
 s none usr/lib/libumem.so=../../lib/libumem.so.1
 s none usr/lib/libumem.so.1=../../lib/libumem.so.1
 s none usr/lib/libuuid.so=../../lib/libuuid.so.1
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386	Fri Mar 24 12:29:20 2006 -0800
@@ -197,6 +197,10 @@
 s none usr/lib/amd64/lib450.so=./lib450.so.1
 s none usr/lib/amd64/libthread_db.so.1=../../../lib/amd64/libc_db.so.1
 s none usr/lib/amd64/libthread_db.so=../../../lib/amd64/libc_db.so.1
+s none usr/lib/amd64/libtsnet.so.1=../../../lib/amd64/libtsnet.so.1
+s none usr/lib/amd64/libtsnet.so=../../../lib/amd64/libtsnet.so.1
+s none usr/lib/amd64/libtsol.so.2=../../../lib/amd64/libtsol.so.2
+s none usr/lib/amd64/libtsol.so=../../../lib/amd64/libtsol.so.2
 s none usr/lib/amd64/libuuid.so.1=../../../lib/amd64/libuuid.so.1
 s none usr/lib/amd64/libuuid.so=../../../lib/amd64/libuuid.so.1
 f none usr/lib/amd64/libvt0.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -288,6 +290,10 @@
 s none usr/lib/sparcv9/libtermlib.so.1=../../../lib/sparcv9/libcurses.so.1
 s none usr/lib/sparcv9/libthread.so.1=../../../lib/sparcv9/libthread.so.1
 s none usr/lib/sparcv9/libthread.so=../../../lib/sparcv9/libthread.so.1
+s none usr/lib/sparcv9/libtsnet.so.1=../../../lib/sparcv9/libtsnet.so.1
+s none usr/lib/sparcv9/libtsnet.so=../../../lib/sparcv9/libtsnet.so.1
+s none usr/lib/sparcv9/libtsol.so.2=../../../lib/sparcv9/libtsol.so.2
+s none usr/lib/sparcv9/libtsol.so=../../../lib/sparcv9/libtsol.so.2
 s none usr/lib/sparcv9/libumem.so=../../../lib/sparcv9/libumem.so.1
 s none usr/lib/sparcv9/libumem.so.1=../../../lib/sparcv9/libumem.so.1
 s none usr/lib/sparcv9/libuutil.so.1=../../../lib/sparcv9/libuutil.so.1
--- a/usr/src/pkgdefs/SUNWcslr/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -144,6 +146,9 @@
 s none lib/libthread.so=libthread.so.1
 s none lib/libthread_db.so.1=libc_db.so.1
 s none lib/libthread_db.so=libc_db.so.1
+f none lib/libtsnet.so.1 755 root bin
+f none lib/libtsol.so.2 755 root bin
+s none lib/libtsol.so=libtsol.so.2
 s none lib/libw.so=libw.so.1
 f none lib/libw.so.1 755 root bin
 s none lib/libumem.so=libumem.so.1
--- a/usr/src/pkgdefs/SUNWcslr/prototype_i386	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_i386	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -140,6 +142,10 @@
 f none lib/amd64/libthread.so.1 755 root bin
 s none lib/amd64/libthread_db.so=libc_db.so.1
 s none lib/amd64/libthread_db.so.1=libc_db.so.1
+s none lib/amd64/libtsnet.so=libtsnet.so.1
+f none lib/amd64/libtsnet.so.1 755 root bin
+s none lib/amd64/libtsol.so=libtsol.so.2
+f none lib/amd64/libtsol.so.2 755 root bin
 s none lib/amd64/libumem.so=libumem.so.1
 f none lib/amd64/libumem.so.1 755 root bin
 s none lib/amd64/libuuid.so=libuuid.so.1
--- a/usr/src/pkgdefs/SUNWcslr/prototype_sparc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_sparc	Fri Mar 24 12:29:20 2006 -0800
@@ -17,6 +17,8 @@
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
+
+
 #
 #
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
@@ -142,6 +144,10 @@
 f none lib/sparcv9/libthread.so.1 755 root bin
 s none lib/sparcv9/libthread_db.so=libc_db.so.1
 s none lib/sparcv9/libthread_db.so.1=libc_db.so.1
+s none lib/sparcv9/libtsnet.so=libtsnet.so.1
+f none lib/sparcv9/libtsnet.so.1 755 root bin
+s none lib/sparcv9/libtsol.so=libtsol.so.2
+f none lib/sparcv9/libtsol.so.2 755 root bin
 s none lib/sparcv9/libumem.so=libumem.so.1
 f none lib/sparcv9/libumem.so.1 0755 root bin
 s none lib/sparcv9/libuuid.so=libuuid.so.1
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -272,10 +272,10 @@
 f none etc/security/dev/st0 400 root bin
 f none etc/security/dev/st1 400 root bin
 d none etc/security/lib 755 root sys
-f none etc/security/lib/audio_clean 751 root sys
-f none etc/security/lib/fd_clean 751 root sys
-f none etc/security/lib/sr_clean 751 root sys
-f none etc/security/lib/st_clean 751 root sys
+f none etc/security/lib/audio_clean 555 root sys
+f none etc/security/lib/fd_clean 555 root sys
+f none etc/security/lib/sr_clean 555 root sys
+f none etc/security/lib/st_clean 555 root sys
 e rbac etc/security/auth_attr 644 root sys
 e rbac etc/security/exec_attr 644 root sys
 e rbac etc/security/prof_attr 644 root sys
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -685,7 +685,7 @@
 f none usr/sbin/6to4relay 555 root bin
 f none usr/sbin/acctadm 555 root bin
 l none usr/sbin/add_drv=../../usr/lib/isaexec
-f none usr/sbin/allocate 4755 root bin
+f none usr/sbin/allocate 4555 root bin
 f none usr/sbin/arp 555 root bin
 f none usr/sbin/audit 555 root bin
 f none usr/sbin/auditconfig 555 root bin
@@ -699,7 +699,7 @@
 f none usr/sbin/clear_locks 555 root bin
 f none usr/sbin/cryptoadm 555 root bin
 l none usr/sbin/deallocate=../../usr/sbin/allocate
-f none usr/sbin/dminfo 755 root bin
+f none usr/sbin/dminfo 555 root bin
 s none usr/sbin/fdisk=../../sbin/fdisk
 f none usr/sbin/ikeadm 555 root bin
 f none usr/sbin/ikecert 555 root bin
@@ -708,8 +708,8 @@
 f none usr/sbin/ipsecconf 555 root bin
 f none usr/sbin/ipseckey 555 root bin
 l none usr/sbin/list_devices=../../usr/sbin/allocate
-f none usr/sbin/mkdevalloc 755 root bin
-f none usr/sbin/mkdevmaps 755 root bin
+f none usr/sbin/mkdevalloc 555 root bin
+l none usr/sbin/mkdevmaps=../../usr/sbin/mkdevalloc
 f none usr/sbin/praudit 555 root bin
 l none usr/sbin/audlinks=./devfsadm
 s none usr/sbin/autopush=../../sbin/autopush
@@ -1562,4 +1562,3 @@
 d none usr/xpg4 755 root bin
 d none usr/xpg4/bin 755 root bin
 f none usr/xpg4/bin/sh 555 root bin
-
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Fri Mar 24 12:29:20 2006 -0800
@@ -189,6 +189,7 @@
 f none usr/include/libsysevent.h 644 root bin
 f none usr/include/libsysevent_impl.h 644 root bin
 f none usr/include/libsvm.h 644 root bin
+f none usr/include/libtsnet.h 644 root bin
 f none usr/include/libw.h 644 root bin
 f none usr/include/libzfs.h 644 root bin
 f none usr/include/libzoneinfo.h 644 root bin
@@ -1110,6 +1111,12 @@
 f none usr/include/sys/tpicommon.h 0644 root bin
 f none usr/include/sys/trap.h 644 root bin
 f none usr/include/sys/ts.h 644 root bin
+d none usr/include/sys/tsol 755 root bin
+f none usr/include/sys/tsol/label.h 644 root bin
+f none usr/include/sys/tsol/label_macro.h 644 root bin
+f none usr/include/sys/tsol/priv.h 644 root bin
+f none usr/include/sys/tsol/tndb.h 644 root bin
+f none usr/include/sys/tsol/tsyscall.h 644 root bin
 f none usr/include/sys/tspriocntl.h 644 root bin
 f none usr/include/sys/ttcompat.h 644 root bin
 f none usr/include/sys/ttold.h 644 root bin
@@ -1173,6 +1180,8 @@
 f none usr/include/thread_db.h 644 root bin
 f none usr/include/time.h 644 root bin
 f none usr/include/tiuser.h 644 root bin
+d none usr/include/tsol 755 root bin
+f none usr/include/tsol/label.h 644 root bin
 f none usr/include/tzfile.h 644 root bin
 f none usr/include/ucontext.h 644 root bin
 f none usr/include/ucred.h 644 root bin
--- a/usr/src/pkgdefs/common_files/i.nsswitch	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/common_files/i.nsswitch	Fri Mar 24 12:29:20 2006 -0800
@@ -3,9 +3,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,7 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -302,6 +300,28 @@
 		sed -e '/^sendmailvars:/d' $dest > /tmp/d.$$
 		cp /tmp/d.$$ $dest
 		rm -f /tmp/d.$$
+
+		# If the file doesn't have Trusted Extensions networking
+		# database (TNdb) entries, add appropriate entries. Default
+		# to everything if we can't figure out what is appropriate.
+		for DB in tnrhtp tnrhdb
+		do
+			grep $DB: $dest > /dev/null 2>&1
+			if [ $? != 0 ]; then
+				ATTR="files ldap"
+				egrep '/etc/nsswitch\.(dns|files)' $dest >\
+				    /dev/null 2>&1
+				if [ $? = 0 ] ; then
+					ATTR="files"
+				fi
+				grep '/etc/nsswitch.ldap' $dest >/dev/null \
+				    2>&1
+				if [ $? = 0 ] ; then
+					ATTR="files ldap"
+				fi
+				echo "${DB}:	${ATTR}" >> $dest
+			fi
+		done
 	fi
 done
 
--- a/usr/src/pkgdefs/etc/exception_list_i386	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Fri Mar 24 12:29:20 2006 -0800
@@ -52,6 +52,7 @@
 usr/include/priv_utils.h	i386
 usr/include/bsm/audit_door_infc.h	i386
 usr/include/bsm/audit_private.h	i386
+usr/include/bsm/devalloc.h	i386
 usr/include/sys/ieeefp.h	i386
 usr/include/sys/winlockio.h	i386
 usr/include/security/pam_impl.h	i386
@@ -782,3 +783,15 @@
 #
 usr/lib/libstanddisasm.so		i386
 usr/lib/amd64/libstanddisasm.so		i386
+
+#
+# TSol: tsol doesn't ship lint source, and tsnet isn't for customers at all.
+lib/libtsnet.so				i386
+lib/llib-ltsnet				i386
+usr/lib/llib-ltsnet			i386
+usr/lib/llib-ltsol			i386
+lib/llib-ltsol				i386
+
+#
+# nss interfaces shared between libnsl and other ON libraries.
+usr/include/nss.h			i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Fri Mar 24 12:29:20 2006 -0800
@@ -43,6 +43,7 @@
 usr/include/priv_utils.h	sparc
 usr/include/bsm/audit_door_infc.h	sparc
 usr/include/bsm/audit_private.h	sparc
+usr/include/bsm/devalloc.h	sparc
 usr/include/security/pam_impl.h	sparc
 usr/include/passwdutil.h	sparc
 #
@@ -847,3 +848,15 @@
 # only used when building the KMDB disasm module.
 #
 usr/lib/sparcv9/libstanddisasm.so	sparc
+
+#
+# TSol: tsol doesn't ship lint source, and tsnet isn't for customers at all.
+lib/libtsnet.so					sparc
+lib/llib-ltsnet					sparc
+usr/lib/llib-ltsnet				sparc
+usr/lib/llib-ltsol				sparc
+lib/llib-ltsol					sparc
+
+#
+# nss interfaces shared between libnsl and other ON libraries.
+usr/include/nss.h				sparc
--- a/usr/src/tools/abi/etc/exceptions	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/tools/abi/etc/exceptions	Fri Mar 24 12:29:20 2006 -0800
@@ -1,13 +1,12 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -366,6 +365,13 @@
 4947729: RULE W3: usr/lib/pool/libjpool.so.1
 4947729: RULE W3: usr/lib/pool/libjsyslog.so.1
 4940032: RULE W3: usr/lib/print/psm-lpsched.so.1
+PSARC 2002/762: RULE W3: lib/libtsnet.so.1
+PSARC 2002/762: RULE W3: usr/lib/libtsol.so.2
+PSARC 2002/762: RULE W3: usr/lib/sparcv9/libtsol.so.2
+PSARC 2002/762: RULE W3: usr/lib/amd64/libtsol.so.2
+PSARC 2002/762: RULE W3: lib/libtsol.so.2
+PSARC 2002/762: RULE W3: lib/sparcv9/libtsol.so.2
+PSARC 2002/762: RULE W3: lib/amd64/libtsol.so.2
 6289029: RULE W3: lib/libdlpi.so.1
  
 #############################################
--- a/usr/src/uts/common/Makefile.files	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/Makefile.files	Fri Mar 24 12:29:20 2006 -0800
@@ -77,6 +77,7 @@
 		bdev_dsort.o	\
 		bio.o		\
 		bitmap.o	\
+		blabel.o	\
 		callb.o		\
 		callout.o	\
 		chdir.o		\
@@ -162,6 +163,7 @@
 		kmem.o		\
 		ksyms_snapshot.o	\
 		l_strplumb.o	\
+		labelsys.o	\
 		link.o		\
 		list.o		\
 		lockstat_subr.o	\
@@ -297,6 +299,7 @@
 		times.o		\
 		timers.o	\
 		thread.o	\
+		tlabel.o	\
 		tnf_res.o	\
 		turnstile.o	\
 		tty_common.o	\
@@ -426,7 +429,7 @@
 		sctp_param.o sctp_shutdown.o sctp_common.o \
 		sctp_timer.o sctp_heartbeat.o sctp_hash.o \
 		sctp_ioc.o sctp_bind.o sctp_notify.o sctp_asconf.o \
-		sctp_addr.o
+		sctp_addr.o tn_ipopt.o tnet.o
 
 IP_OBJS +=	igmp.o ip.o ip6.o ip6_asp.o ip6_if.o ip6_ire.o ip6_rts.o \
 		ip_cksum.o ip_if.o ip_ire.o ip_listutils.o ip_mroute.o \
--- a/usr/src/uts/common/Makefile.rules	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/Makefile.rules	Fri Mar 24 12:29:20 2006 -0800
@@ -828,6 +828,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(COMMONBASE)/tsol/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(COMMONBASE)/util/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1467,6 +1471,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/tnf/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(COMMONBASE)/tsol/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(COMMONBASE)/util/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/c2/audit.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -64,6 +63,7 @@
 #include <sys/devpolicy.h>
 #include <sys/crypto/ioctladmin.h>
 #include <inet/kssl/kssl.h>
+#include <sys/tsol/label.h>
 
 static void add_return_token(caddr_t *, unsigned int scid, int err, int rval);
 
@@ -300,6 +300,8 @@
 			return (0);
 	}
 
+	tad->tad_ctrl |= PAD_NOPATH;		/* prevent possible reentry */
+
 	audit_pathbuild(pnp);
 	tad->tad_vn = vp;
 
@@ -348,6 +350,7 @@
 	if (tad->tad_ctrl & PAD_MLD)
 		tad->tad_ctrl |= PAD_PATHFND;
 
+	tad->tad_ctrl &= ~PAD_NOPATH;		/* restore */
 	return (0);
 }
 
@@ -703,6 +706,7 @@
 			tad->tad_ctrl |= PAD_NOAUDIT;
 		} else {
 			au_uwrite(au_to_attr(&attr));
+			audit_sec_attributes(&(u_ad), vp);
 		}
 	}
 }
@@ -920,6 +924,10 @@
 		/* Add an optional group token */
 		AUDIT_SETGROUP(&(u_ad), cr, kctx);
 
+		/* Add slabel token */
+		if (is_system_labeled())
+			au_write(&(u_ad), au_to_label(CR_SL(cr)));
+
 		/* Add a return token (should use f argument) */
 		add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
 
@@ -1124,6 +1132,7 @@
 
 	if (getattr_ret == 0) {
 		au_write((caddr_t *)&(ad), au_to_attr(&attr));
+		audit_sec_attributes((caddr_t *)&(ad), vp);
 	}
 
 	/* Add a subject token */
@@ -1132,6 +1141,10 @@
 	/* add an optional group token */
 	AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx);
 
+	/* add slabel token */
+	if (is_system_labeled())
+		au_write((caddr_t *)&(ad), au_to_label(CR_SL(cr)));
+
 	/* add a return token */
 	add_return_token((caddr_t *)&(ad), tad->tad_scid, 0, 0);
 
@@ -1325,6 +1338,10 @@
 		/* add an optional group token */
 		AUDIT_SETGROUP(&(u_ad), cr, kctx);
 
+		/* add slabel token */
+		if (is_system_labeled())
+			au_uwrite(au_to_label(CR_SL(cr)));
+
 		/* add a return token */
 		add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
 
@@ -2158,6 +2175,10 @@
 	/* add an optional group token */
 	AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx);
 
+	/* add slabel token */
+	if (is_system_labeled())
+		au_write((caddr_t *)&ad, au_to_label(CR_SL(cr)));
+
 	switch (cmd) {
 	case CRYPTO_LOAD_DEV_DISABLED:
 		if (error == 0 && rv == CRYPTO_SUCCESS) {
@@ -2307,6 +2328,10 @@
 	/* add an optional group token */
 	AUDIT_SETGROUP((caddr_t *)&ad, cr, kctx);
 
+	/* Add slabel token */
+	if (is_system_labeled())
+		au_write(&(u_ad), au_to_label(CR_SL(cr)));
+
 	switch (cmd) {
 	case KSSL_ADD_ENTRY: {
 		char buf[32];
@@ -2349,3 +2374,35 @@
 
 	au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CONFIGKSSL, 0);
 }
+
+/*
+ * ROUTINE:	AUDIT_SEC_ATTRIBUTES
+ * PURPOSE:	Add security attributes
+ * CALLBY:	AUDIT_ATTRIBUTES
+ *		AUDIT_CLOSEF
+ *		AUS_CLOSE
+ * NOTE:
+ * TODO:
+ * QUESTION:
+ */
+
+void
+audit_sec_attributes(caddr_t *ad, struct vnode *vp)
+{
+	/* Dump the SL */
+	if (is_system_labeled()) {
+		ts_label_t	*tsl;
+		bslabel_t	*bsl;
+
+		tsl = getflabel(vp);
+		if (tsl == NULL)
+			return;			/* nothing else to do */
+
+		bsl = label2bslabel(tsl);
+		if (bsl == NULL)
+			return;			/* nothing else to do */
+		au_write(ad, au_to_label(bsl));
+		label_rele(tsl);
+	}
+
+}	/* AUDIT_SEC_ATTRIBUTES */
--- a/usr/src/uts/common/c2/audit.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -271,12 +270,21 @@
 #define	AUDIT_WINDATA	0x0040	/* include interwindow moved data */
 #define	AUDIT_USER	0x0080	/* make audituser(2) un-privileged */
 #define	AUDIT_GROUP	0x0100	/* include group attribute with each record */
-#define	AUDIT_TRAIL	0X0200	/* include trailer token */
+#define	AUDIT_TRAIL	0x0200	/* include trailer token */
 #define	AUDIT_PATH	0x0400	/* allow multiple paths per event */
 #define	AUDIT_SCNT	0x0800	/* sleep user events but not kernel events */
 #define	AUDIT_PUBLIC	0x1000	/* audit even "public" files */
 #define	AUDIT_ZONENAME	0x2000	/* emit zonename token */
 #define	AUDIT_PERZONE	0x4000	/* auditd and audit queue for each zone */
+
+/*
+ * These next (WINDATA*) are used by TSOL. Although per-zone audit is not
+ * used with TSOL, these policies still make sense to be categorized as
+ * "local".
+ */
+#define	AUDIT_WINDATA_DOWN	0x00010000	/* include downgraded data */
+#define	AUDIT_WINDATA_UP	0x00020000	/* include upgraded data */
+
 /*
  * If AUDIT_GLOBAL changes, corresponding changes are required in
  * audit_syscalls.c's setpolicy().
@@ -285,7 +293,8 @@
 #define	AUDIT_LOCAL	(AUDIT_CNT | AUDIT_ARGV | AUDIT_ARGE |\
 			AUDIT_PASSWD | AUDIT_SEQ | AUDIT_WINDATA |\
 			AUDIT_USER | AUDIT_GROUP | AUDIT_TRAIL | AUDIT_PATH |\
-			AUDIT_PUBLIC | AUDIT_SCNT | AUDIT_ZONENAME)
+			AUDIT_PUBLIC | AUDIT_SCNT | AUDIT_ZONENAME |\
+			AUDIT_WINDATA_DOWN | AUDIT_WINDATA_UP)
 
 /*
  * Kernel audit queue control parameters
@@ -580,6 +589,7 @@
 void	audit_devpolicy(int, const struct devplcysys *);
 void	audit_update_context(proc_t *, cred_t *);
 void	audit_kssl(int, void *, int);
+void	audit_sec_attributes(caddr_t *, struct vnode *);
 
 #endif
 
--- a/usr/src/uts/common/c2/audit_event.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit_event.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,6 +55,7 @@
 #include <sys/kmem.h>
 #include <sys/file.h>		/* for accept */
 #include <sys/utssys.h>		/* for fuser */
+#include <sys/tsol/label.h>
 #include <c2/audit.h>
 #include <c2/audit_kernel.h>
 #include <c2/audit_kevents.h>
@@ -1432,6 +1432,10 @@
 		rgid = crgetrgid(cr);
 		au_uwrite(au_to_process(uid, gid, ruid, rgid, pid,
 		    ainfo->ai_auid, ainfo->ai_asid, &ainfo->ai_termid));
+
+		if (is_system_labeled())
+			au_uwrite(au_to_label(CR_SL(cr)));
+
 		crfree(cr);
 	}
 	else
@@ -1865,7 +1869,6 @@
 		if ((vp = fp->f_vnode) != NULL) {
 			attr.va_mask = AT_ALL;
 			if (VOP_GETATTR(vp, &attr, 0, CRED()) == 0) {
-				au_uwrite(au_to_attr(&attr));
 				/*
 				 * When write was not used and the file can be
 				 * considered public, skip the audit.
@@ -1879,6 +1882,8 @@
 					releasef(fd);
 					return;
 				}
+				au_uwrite(au_to_attr(&attr));
+				audit_sec_attributes(&(u_ad), vp);
 			}
 		}
 	}
--- a/usr/src/uts/common/c2/audit_kevents.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit_kevents.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,7 +37,7 @@
  *
  *	0		Reserved as an invalid event number.
  *	1 -   511	Allocated for Solaris kernel
- *	512 -  1023	Allocated for Trusted Solaris kernel
+ *	512 -  1023	Allocated for Trusted Solaris/Trusted Extensions kernel
  *	1024 -  2047	(reserved but not allocated)
  *	2048 - 32767	Reserved for the Solaris TCB application.
  *	32768 - 65535	Available for other Trusted applications.
@@ -165,11 +164,9 @@
 #define	AUE_ASYNC_DAEMON_EXIT	114	/* =no async_daemon(2) exited */
 #define	AUE_NFSSVC_EXIT		115	/* =no nfssvc(2) exited */
 /*
- * 116 - 127 are available for future growth (old SunOS_CMW events
+ * 116 - 129 are available for future growth (old SunOS_CMW events
  * that had no libbsm or praudit support or references)
  */
-#define	AUE_WRITEL		128	/* =no writel(2) */
-#define	AUE_WRITEVL		129	/* =no writevl(2) */
 #define	AUE_GETAUID		130	/* =aa getauid(2) */
 #define	AUE_SETAUID		131	/* =aa setauid(2) */
 #define	AUE_GETAUDIT		132	/* =aa getaudit(2) */
@@ -219,10 +216,10 @@
 #define	AUE_MSGSNDL		176	/* =no msgsndl(2) */
 #define	AUE_SEMGETL		177	/* =no semgetl(2) */
 #define	AUE_SHMGETL		178	/* =no shmgetl(2) */
-#define	AUE_GETMLDADORN		179	/* =no getmldadorn(2) */
-#define	AUE_GETSLDNAME		180	/* =no getsldname(2) */
-#define	AUE_MLDLSTAT		181	/* =no mldlstat(2) */
-#define	AUE_MLDSTAT		182	/* =no mldstat(2) */
+/*				179	    OBSOLETE */
+/*				180	    OBSOLETE */
+/*				181	    OBSOLETE */
+/*				182	    OBSOLETE */
 #define	AUE_SOCKET		183	/* =nt socket(2) */
 #define	AUE_SENDTO		184	/* =nt sendto(2) */
 #define	AUE_PIPE		185	/* =no pipe(2) */
@@ -336,12 +333,17 @@
 #define	AUE_CONFIGKSSL		293	/* =as kernel SSL */
 
 /*
+ * Trusted Solaris/Trusted Extensions kernel audit events
+ *	512 -  1023	allocated for Trusted Solaris/Trusted Extensions
+ */
+
+/*
  * Maximum number of kernel events in the event to class table
  * leave a couple extra ones just incase somebody wants to load a new
  * driver with build in auditing
  */
 
-#define	MAX_KEVENTS		512
+#define	MAX_KEVENTS		580
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/c2/audit_record.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit_record.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,9 +36,7 @@
 #include <sys/socket.h>
 #include <sys/acl.h>
 
-#if defined(TSOL) && defined(_KERNEL)
 #include <sys/tsol/label.h>
-#endif /* TSOL && _KERNEL */
 
 #ifdef __cplusplus
 extern "C" {
@@ -303,15 +300,7 @@
 token_t *au_to_sock_inet(struct sockaddr_in *);
 token_t *au_to_exec_args(const char *, ssize_t);
 token_t *au_to_exec_env(const char *, ssize_t);
-
-#ifdef TSOL
-token_t	*au_to_clearance(bclear_t *);
-token_t	*au_to_host(void);
-token_t	*au_to_ilabel(bilabel_t *);
-token_t	*au_to_priv(priv_t, int);
-token_t	*au_to_privilege(priv_set_t *, char);
-token_t	*au_to_slabel(bslabel_t *);
-#endif	/* TSOL */
+token_t	*au_to_label(bslabel_t *);
 token_t	*au_to_privset(const char *, const priv_set_t *, char, int);
 
 void	au_uwrite();
@@ -735,6 +724,7 @@
 extern token_t *au_to_ipc_perm(struct ipc_perm *);
 extern token_t *au_to_iport(ushort_t);
 extern token_t *au_to_me(void);
+extern token_t *au_to_mylabel(void);
 extern token_t *au_to_opaque(char *, short);
 extern token_t *au_to_path(char *);
 extern token_t *au_to_privset(const char *, const priv_set_t *);
@@ -745,6 +735,7 @@
 extern token_t *au_to_return32(char, uint32_t);
 extern token_t *au_to_return64(char, uint64_t);
 extern token_t *au_to_seq(int);
+extern token_t *au_to_label(bslabel_t *);
 extern token_t *au_to_socket(struct oldsocket *);
 extern token_t *au_to_socket_ex(short, short,
 				struct sockaddr *, struct sockaddr *);
--- a/usr/src/uts/common/c2/audit_start.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit_start.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,6 +43,7 @@
 #include <sys/debug.h>
 #include <sys/cred_impl.h>
 #include <sys/zone.h>
+#include <sys/tsol/label.h>
 #include <c2/audit.h>
 #include <c2/audit_kernel.h>
 #include <c2/audit_kevents.h>
@@ -428,6 +428,10 @@
 			/* Add an optional group token */
 			AUDIT_SETGROUP(&(u_ad), cr, kctx);
 
+			/* Add token for process SL */
+			if (is_system_labeled())
+				au_write(&(u_ad), au_to_label(CR_SL(cr)));
+
 			if (tad->tad_evmod & PAD_SPRIVUSE)
 				au_write(&(u_ad),
 					au_to_privset("", &tad->tad_sprivs,
--- a/usr/src/uts/common/c2/audit_token.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/c2/audit_token.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -54,6 +53,7 @@
 #include <sys/vfs.h>		/* for sonode */
 #include <sys/socketvar.h>	/* for sonode */
 #include <sys/zone.h>
+#include <sys/tsol/label.h>
 
 /*
  * These are the control tokens
@@ -928,33 +928,6 @@
 	return (m);
 }
 
-#ifdef NOTYET
-/*
- * au_to_label
- * returns:
- *	pointer to au_membuf chain containing a label token.
- */
-token_t *
-au_to_label(bilabel_t *label)
-{
-	token_t *m;			/* local au_membuf */
-	adr_t adr;			/* adr memory stream header */
-	char data_header = AUT_LABEL;	/* header for this token */
-	short bs = sizeof (bilabel_t);
-
-	m = au_getclr();
-
-	adr_start(&adr, memtod(m, char *));
-	adr_char(&adr, &data_header, 1);
-	adr_short(&adr, &bs, 1);
-	adr_char(&adr, (char *)label, bs);
-
-	m->len = adr_count(&adr);
-
-	return (m);
-}
-#endif	/* NOTYET */
-
 token_t *
 au_to_groups(const gid_t *crgroups, uint_t crngroups)
 {
@@ -1144,3 +1117,25 @@
 
 	return (token);
 }
+
+/*
+ * au_to_label
+ * returns:
+ *	pointer to au_membuf chain containing a sensitivity label token.
+ */
+token_t *
+au_to_label(bslabel_t *label)
+{
+	token_t *m;			/* local au_membuf */
+	adr_t adr;			/* adr memory stream header */
+	char data_header = AUT_LABEL;	/* header for this token */
+
+	m = au_getclr();
+
+	adr_start(&adr, memtod(m, char *));
+	adr_char(&adr, &data_header, 1);
+	adr_char(&adr, (char *)label, sizeof (bslabel_t));
+	m->len = adr_count(&adr);
+
+	return (m);
+}
--- a/usr/src/uts/common/disp/thread.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/disp/thread.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -67,6 +66,8 @@
 #include <sys/rctl.h>
 #include <sys/pool.h>
 #include <sys/zone.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tndb.h>
 #include <sys/cpc_impl.h>
 #include <sys/sdt.h>
 #include <sys/reboot.h>
@@ -178,12 +179,14 @@
 	    sizeof (turnstile_t), 0,
 	    turnstile_constructor, turnstile_destructor, NULL, NULL, NULL, 0);
 
+	label_init();
 	cred_init();
 
 	rctl_init();
 	project_init();
 	zone_init();
 	task_init();
+	tcache_init();
 	pool_init();
 
 	curthread->t_ts = kmem_cache_alloc(turnstile_cache, KM_SLEEP);
--- a/usr/src/uts/common/fs/autofs/auto_vfsops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/autofs/auto_vfsops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -39,18 +39,15 @@
 #include <sys/tiuser.h>
 #include <sys/cmn_err.h>
 #include <sys/debug.h>
-#include <sys/mkdev.h>
 #include <sys/systm.h>
 #include <sys/sysmacros.h>
 #include <sys/pathname.h>
 #include <rpc/types.h>
 #include <rpc/auth.h>
 #include <rpc/clnt.h>
-#include <sys/dnlc.h>
 #include <fs/fs_subr.h>
 #include <sys/fs/autofs.h>
 #include <rpcsvc/autofs_prot.h>
-#include <sys/note.h>
 #include <sys/modctl.h>
 #include <sys/mntent.h>
 #include <sys/policy.h>
--- a/usr/src/uts/common/fs/doorfs/door_vnops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/doorfs/door_vnops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,7 +33,8 @@
 #include <sys/debug.h>
 #include <sys/cmn_err.h>
 #include <fs/fs_subr.h>
-
+#include <sys/zone.h>
+#include <sys/tsol/label.h>
 
 kmutex_t	door_knob;
 static int	door_open(struct vnode **vpp, int flag, struct cred *cr);
@@ -71,6 +71,27 @@
 static int
 door_open(struct vnode **vpp, int flag, struct cred *cr)
 {
+	/*
+	 * MAC policy for doors.  Restrict cross-zone open()s so that only
+	 * door servers in the global zone can have clients from other zones.
+	 * For other zones, client must be within the same zone as server.
+	 */
+	if (is_system_labeled()) {
+		zone_t		*server_zone, *client_zone;
+		door_node_t	*dp = VTOD((*vpp));
+
+		mutex_enter(&door_knob);
+		if (DOOR_INVALID(dp)) {
+			mutex_exit(&door_knob);
+			return (0);
+		}
+		client_zone = curproc->p_zone;
+		server_zone = dp->door_target->p_zone;
+		mutex_exit(&door_knob);
+		if (server_zone != global_zone &&
+		    server_zone != client_zone)
+			return (EACCES);
+	}
 	return (0);
 }
 
--- a/usr/src/uts/common/fs/lofs/lofs_vfsops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/lofs/lofs_vfsops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -39,10 +39,12 @@
 #include <sys/mount.h>
 #include <sys/mntent.h>
 #include <sys/mkdev.h>
+#include <sys/priv.h>
 #include <sys/sysmacros.h>
 #include <sys/systm.h>
 #include <sys/cmn_err.h>
 #include <sys/policy.h>
+#include <sys/tsol/label.h>
 #include "fs/fs_subr.h"
 
 /*
@@ -118,8 +120,9 @@
 /*
  * This is the module initialization routine.
  */
+
 int
-_init()
+_init(void)
 {
 	int status;
 
@@ -139,8 +142,9 @@
  * Don't allow the lofs module to be unloaded for now.
  * There is a memory leak if it gets unloaded.
  */
+
 int
-_fini()
+_fini(void)
 {
 	return (EBUSY);
 }
@@ -203,7 +207,7 @@
 
 	mutex_enter(&vp->v_lock);
 	if (!(uap->flags & MS_OVERLAY) &&
-		(vp->v_count != 1 || (vp->v_flag & VROOT))) {
+	    (vp->v_count != 1 || (vp->v_flag & VROOT))) {
 		mutex_exit(&vp->v_lock);
 		return (EBUSY);
 	}
@@ -218,6 +222,95 @@
 		return (error);
 
 	/*
+	 * Enforce MAC policy if needed.
+	 *
+	 * Loopback mounts must not allow writing up. The dominance test
+	 * is intended to prevent a global zone caller from accidentally
+	 * creating write-up conditions between two labeled zones.
+	 * Local zones can't violate MAC on their own without help from
+	 * the global zone because they can't name a pathname that
+	 * they don't already have.
+	 *
+	 * The special case check for the NET_MAC_AWARE process flag is
+	 * to support the case of the automounter in the global zone. We
+	 * permit automounting of local zone directories such as home
+	 * directories, into the global zone as required by setlabel,
+	 * zonecopy, and saving of desktop sessions. Such mounts are
+	 * trusted not to expose the contents of one zone's directories
+	 * to another by leaking them through the global zone.
+	 */
+	if (is_system_labeled() && crgetzoneid(cr) == GLOBAL_ZONEID) {
+		void *specname;
+		zone_t *from_zptr;
+		zone_t *to_zptr;
+
+		if (uap->flags & MS_SYSSPACE) {
+			specname = uap->spec;
+		} else {
+			specname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+			error = copyinstr(uap->spec, specname, MAXPATHLEN,
+			    NULL);
+			if (error) {
+				kmem_free(specname, MAXPATHLEN);
+				return (error);
+			}
+		}
+		from_zptr = zone_find_by_path(specname);
+		if (!(uap->flags & MS_SYSSPACE))
+			kmem_free(specname, MAXPATHLEN);
+
+		to_zptr = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
+
+		/*
+		 * Special case for zone devfs: the zone for /dev will
+		 * incorrectly appear as the global zone since it's not
+		 * under the zone rootpath.  So for zone devfs check allow
+		 * read-write mounts.
+		 */
+
+		if (from_zptr != to_zptr && !is_zonedevfs) {
+			/*
+			 * We know at this point that the labels aren't equal
+			 * because the zone pointers aren't equal, and zones
+			 * can't share a label.
+			 *
+			 * If the source is the global zone then making
+			 * it available to a local zone must be done in
+			 * read-only mode as the label will become admin_low.
+			 *
+			 * If it is a mount between local zones then if
+			 * the current process is in the global zone and has
+			 * the NET_MAC_AWARE flag, then regular read-write
+			 * access is allowed.  If it's in some other zone, but
+			 * the label on the mount point dominates the original
+			 * source, then allow the mount as read-only
+			 * ("read-down").
+			 */
+			if (from_zptr->zone_id == GLOBAL_ZONEID) {
+				/* make the mount read-only */
+				vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+			} else { /* cross-zone mount */
+				if (to_zptr->zone_id == GLOBAL_ZONEID &&
+				    /* LINTED: no consequent */
+				    getpflags(NET_MAC_AWARE, cr) != 0) {
+					/* Allow the mount as read-write */
+				} else if (bldominates(
+				    label2bslabel(to_zptr->zone_slabel),
+				    label2bslabel(from_zptr->zone_slabel))) {
+					/* make the mount read-only */
+					vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+				} else {
+					zone_rele(to_zptr);
+					zone_rele(from_zptr);
+					return (EACCES);
+				}
+			}
+		}
+		zone_rele(to_zptr);
+		zone_rele(from_zptr);
+	}
+
+	/*
 	 * realrootvp may be an AUTOFS node, in which case we
 	 * perform a VOP_ACCESS() to trigger the mount of the
 	 * intended filesystem, so we loopback mount the intended
--- a/usr/src/uts/common/fs/nfs/nfs3_vfsops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs3_vfsops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -57,6 +56,7 @@
 #include <sys/class.h>
 #include <sys/socket.h>
 #include <sys/netconfig.h>
+#include <sys/tsol/tnet.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -222,6 +222,7 @@
 	int flags, addr_type;
 	char *p, *pf;
 	zone_t *zone = nfs_zone();
+	zone_t *mntzone = NULL;
 
 	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 		return (EPERM);
@@ -680,22 +681,34 @@
 	/*
 	 * Determine the zone we're being mounted into.
 	 */
+	zone_hold(mntzone = zone);		/* start with this assumption */
 	if (getzoneid() == GLOBAL_ZONEID) {
-		zone_t *mntzone;
-
+		zone_rele(mntzone);
 		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 		ASSERT(mntzone != NULL);
-		zone_rele(mntzone);
 		if (mntzone != zone) {
 			error = EBUSY;
 			goto errout;
 		}
 	}
 
+	if (is_system_labeled()) {
+		error = nfs_mount_label_policy(vfsp, &svp->sv_addr,
+		    svp->sv_knconf, cr);
+
+		if (error > 0)
+			goto errout;
+
+		if (error == -1) {
+			/* change mount to read-only to prevent write-down */
+			vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+		}
+	}
+
 	/*
 	 * Stop the mount from going any further if the zone is going away.
 	 */
-	if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
+	if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
 		error = EBUSY;
 		goto errout;
 	}
@@ -704,7 +717,7 @@
 	 * Get root vnode.
 	 */
 proceed:
-	error = nfs3rootvp(&rtvp, vfsp, svp_head, flags, cr, zone);
+	error = nfs3rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone);
 
 	if (error)
 		goto errout;
@@ -745,6 +758,9 @@
 	if (rtvp != NULL)
 		VN_RELE(rtvp);
 
+	if (mntzone != NULL)
+		zone_rele(mntzone);
+
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -54,6 +53,7 @@
 #include <sys/atomic.h>
 #include <sys/policy.h>
 #include <sys/fem.h>
+#include <sys/sdt.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -72,6 +72,9 @@
 #include <inet/ip.h>
 #include <inet/ip6.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tndb.h>
+
 #define	RFS4_MAXLOCK_TRIES 4	/* Try to get the lock this many times */
 static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
 #define	RFS4_LOCK_DELAY 10	/* Milliseconds */
@@ -135,6 +138,12 @@
 #define	DIRENT64_TO_DIRCOUNT(dp) \
 	(3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
 
+/*
+ * types of label comparison
+ */
+#define	EQUALITY_CHECK	0
+#define	DOMINANCE_CHECK	1
+
 time_t rfs4_start_time;			/* Initialized in rfs4_srvrinit */
 
 static sysid_t lockt_sysid;		/* dummy sysid for all LOCKT calls */
@@ -1164,6 +1173,32 @@
 	resp->SECINFO4resok_val = NULL;
 }
 
+/*
+ * do label check on client label and server's file lable.
+ */
+static boolean_t
+do_rfs4_label_check(bslabel_t *clabel, vnode_t *vp, int flag)
+{
+	bslabel_t *slabel;
+	ts_label_t *tslabel;
+	boolean_t result;
+
+	if ((tslabel = nfs4_getflabel(vp)) == NULL) {
+		return (B_FALSE);
+	}
+	slabel = label2bslabel(tslabel);
+	DTRACE_PROBE4(tx__rfs4__log__info__labelcheck, char *,
+	    "comparing server's file label(1) with client label(2) (vp(3))",
+	    bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
+
+	if (flag == EQUALITY_CHECK)
+		result = blequal(clabel, slabel);
+	else
+		result = bldominates(clabel, slabel);
+	label_rele(tslabel);
+	return (result);
+}
+
 /* ARGSUSED */
 static void
 rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
@@ -1176,6 +1211,9 @@
 	struct vattr va;
 	int checkwriteperm;
 	cred_t *cr = cs->cr;
+	bslabel_t *clabel, *slabel;
+	ts_label_t *tslabel;
+	boolean_t admin_low_client;
 
 #if 0	/* XXX allow access even if !cs->access. Eventually only pseudo fs */
 	if (cs->access == CS_ACCESS_DENIED) {
@@ -1217,26 +1255,51 @@
 		*cs->statusp = resp->status = puterrno4(error);
 		return;
 	}
-
 	resp->access = 0;
 	resp->supported = 0;
 
+	if (is_system_labeled()) {
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if ((tslabel = nfs4_getflabel(vp)) == NULL) {
+				*cs->statusp = resp->status = puterrno4(EACCES);
+				return;
+			}
+			slabel = label2bslabel(tslabel);
+			DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel,
+			    char *, "got server label(1) for vp(2)",
+			    bslabel_t *, slabel, vnode_t *, vp);
+
+			admin_low_client = B_FALSE;
+		} else
+			admin_low_client = B_TRUE;
+	}
+
 	if (args->access & ACCESS4_READ) {
 		error = VOP_ACCESS(vp, VREAD, 0, cr);
-		if (!error && !MANDLOCK(vp, va.va_mode))
+		if (!error && !MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client ||
+		    bldominates(clabel, slabel)))
 			resp->access |= ACCESS4_READ;
 		resp->supported |= ACCESS4_READ;
 	}
 	if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
 		error = VOP_ACCESS(vp, VEXEC, 0, cr);
-		if (!error)
+		if (!error && (!is_system_labeled() || admin_low_client ||
+		    bldominates(clabel, slabel)))
 			resp->access |= ACCESS4_LOOKUP;
 		resp->supported |= ACCESS4_LOOKUP;
 	}
 	if (checkwriteperm &&
 	    (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
 		error = VOP_ACCESS(vp, VWRITE, 0, cr);
-		if (!error && !MANDLOCK(vp, va.va_mode))
+		if (!error && !MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client ||
+		    blequal(clabel, slabel)))
 			resp->access |=
 			    (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND));
 		resp->supported |= (ACCESS4_MODIFY|ACCESS4_EXTEND);
@@ -1245,17 +1308,23 @@
 	if (checkwriteperm &&
 	    (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
 		error = VOP_ACCESS(vp, VWRITE, 0, cr);
-		if (!error)
+		if (!error && (!is_system_labeled() || admin_low_client ||
+		    blequal(clabel, slabel)))
 			resp->access |= ACCESS4_DELETE;
 		resp->supported |= ACCESS4_DELETE;
 	}
 	if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
 		error = VOP_ACCESS(vp, VEXEC, 0, cr);
-		if (!error && !MANDLOCK(vp, va.va_mode))
+		if (!error && !MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client ||
+		    bldominates(clabel, slabel)))
 			resp->access |= ACCESS4_EXECUTE;
 		resp->supported |= ACCESS4_EXECUTE;
 	}
 
+	if (is_system_labeled() && !admin_low_client)
+		label_rele(tslabel);
+
 	*cs->statusp = resp->status = NFS4_OK;
 }
 
@@ -2541,8 +2610,62 @@
 		}
 	}
 
+	/*
+	 * After various NFS checks, do a label check on the path
+	 * component. The label on this path should either be the
+	 * global zone's label or a zone's label. We are only
+	 * interested in the zone's label because exported files
+	 * in global zone is accessible (though read-only) to
+	 * clients. The exportability/visibility check is already
+	 * done before reaching this code.
+	 */
+	if (is_system_labeled()) {
+		bslabel_t *clabel;
+
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *,
+		    "got client label from request(1)", struct svc_req *, req);
+
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs4_label_check(clabel, vp, DOMINANCE_CHECK)) {
+				error = EACCES;
+				goto err_out;
+			}
+		} else {
+			/*
+			 * We grant access to admin_low label clients
+			 * only if the client is trusted, i.e. also
+			 * running Solaris Trusted Extension.
+			 */
+			struct sockaddr	*ca;
+			int		addr_type;
+			void		*ipaddr;
+			tsol_tpc_t	*tp;
+
+			ca = (struct sockaddr *)svc_getrpccaller(
+			    req->rq_xprt)->buf;
+			if (ca->sa_family == AF_INET) {
+				addr_type = IPV4_VERSION;
+				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
+			} else if (ca->sa_family == AF_INET6) {
+				addr_type = IPV6_VERSION;
+				ipaddr = &((struct sockaddr_in6 *)
+				    ca)->sin6_addr;
+			}
+			tp = find_tpc(ipaddr, addr_type, B_FALSE);
+			if (tp == NULL || tp->tpc_tp.tp_doi !=
+			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
+			    SUN_CIPSO) {
+				error = EACCES;
+				goto err_out;
+			}
+		}
+	}
+
 	error = makefh4(&cs->fh, vp, cs->exi);
 
+err_out:
 	if (error) {
 		if (is_newvp) {
 			VN_RELE(cs->vp);
@@ -3575,6 +3698,7 @@
 	uint_t len;
 	rfs4_file_t *fp;
 	int in_crit = 0;
+	bslabel_t *clabel;
 
 	/* CURRENT_FH: directory */
 	dvp = cs->vp;
@@ -3669,6 +3793,29 @@
 		}
 	}
 
+	/* check label before allowing removal */
+	if (is_system_labeled()) {
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs4_label_check(clabel, vp, EQUALITY_CHECK)) {
+				*cs->statusp = resp->status = NFS4ERR_ACCESS;
+				kmem_free(nm, len);
+				if (in_crit)
+					nbl_end_crit(vp);
+				VN_RELE(vp);
+				if (fp) {
+					rfs4_clear_dont_grant(fp);
+					rfs4_file_rele(fp);
+				}
+				return;
+			}
+		}
+	}
+
 	/* Get dir "before" change value */
 	bdva.va_mask = AT_CTIME|AT_SEQ;
 	error = VOP_GETATTR(dvp, &bdva, 0, cs->cr);
@@ -3809,6 +3956,7 @@
 	rfs4_file_t *fp, *sfp;
 	int in_crit_src, in_crit_targ;
 	int fp_rele_grant_hold, sfp_rele_grant_hold;
+	bslabel_t *clabel;
 
 	fp = sfp = NULL;
 	srcvp = targvp = NULL;
@@ -3900,6 +4048,22 @@
 		return;
 	}
 
+	/* check label of the target dir */
+	if (is_system_labeled()) {
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__oprename__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs4_label_check(clabel, ndvp,
+			    EQUALITY_CHECK)) {
+				*cs->statusp = resp->status = NFS4ERR_ACCESS;
+				return;
+			}
+		}
+	}
+
 	/*
 	 * Is the source a file and have a delegation?
 	 * We don't need to acquire va_seq before these lookups, if
@@ -4712,6 +4876,7 @@
 {
 	SETATTR4args *args = &argop->nfs_argop4_u.opsetattr;
 	SETATTR4res *resp = &resop->nfs_resop4_u.opsetattr;
+	bslabel_t *clabel;
 
 	if (cs->vp == NULL) {
 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
@@ -4734,6 +4899,22 @@
 		return;
 	}
 
+	/* check label before setting attributes */
+	if (is_system_labeled()) {
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__opsetattr__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs4_label_check(clabel, cs->vp,
+			    EQUALITY_CHECK)) {
+				*cs->statusp = resp->status = NFS4ERR_ACCESS;
+				return;
+			}
+		}
+	}
+
 	*cs->statusp = resp->status =
 		do_rfs4_op_setattr(&resp->attrsset, &args->obj_attributes, cs,
 			&args->stateid);
@@ -5187,6 +5368,14 @@
 		crfree(cs.basecr);
 	if (cs.cr)
 		crfree(cs.cr);
+	/*
+	 * done with this compound request, free the label
+	 */
+
+	if (req->rq_label != NULL) {
+		kmem_free(req->rq_label, sizeof (bslabel_t));
+		req->rq_label = NULL;
+	}
 }
 
 /*
@@ -5577,6 +5766,7 @@
 	bool_t trunc;
 	caller_context_t ct;
 	component4 *component;
+	bslabel_t *clabel;
 
 	sarg.sbp = &sb;
 
@@ -5586,6 +5776,20 @@
 	if (rdonly4(cs->exi, dvp, req))
 		return (NFS4ERR_ROFS);
 
+	/* check the label of including directory */
+	if (is_system_labeled()) {
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs4_label_check(clabel, dvp, EQUALITY_CHECK)) {
+				return (NFS4ERR_ACCESS);
+			}
+		}
+	}
+
 	/*
 	 * Get the last component of path name in nm. cs will reference
 	 * the including directory on success.
--- a/usr/src/uts/common/fs/nfs/nfs4_subr.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,9 +38,10 @@
 #include <sys/session.h>
 #include <sys/thread.h>
 #include <sys/dnlc.h>
-#include <sys/cred.h>
+#include <sys/cred_impl.h>
 #include <sys/list.h>
 #include <sys/sdt.h>
+#include <sys/policy.h>
 
 #include <rpc/types.h>
 #include <rpc/xdr.h>
@@ -1208,17 +1208,19 @@
 
 static int
 nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp,
-    xdrproc_t xdrres, caddr_t resp, cred_t *cr, int *doqueue,
+    xdrproc_t xdrres, caddr_t resp, cred_t *icr, int *doqueue,
     enum clnt_stat *rpc_statusp, int flags, struct nfs4_clnt *nfscl)
 {
 	CLIENT *client;
 	struct chtab *ch;
+	cred_t *cr = icr;
 	struct rpc_err rpcerr;
 	enum clnt_stat status;
 	int error;
 	struct timeval wait;
 	int timeo;		/* in units of hz */
 	bool_t tryagain, is_recov;
+	bool_t cred_cloned = FALSE;
 	k_sigset_t smask;
 	servinfo4_t *svp;
 #ifdef DEBUG
@@ -1239,6 +1241,13 @@
 	}
 	mutex_exit(&mi->mi_lock);
 
+	/* For TSOL, use a new cred which has net_mac_aware flag */
+	if (!cred_cloned && is_system_labeled()) {
+		cred_cloned = TRUE;
+		cr = crdup(icr);
+		(void) setpflags(NET_MAC_AWARE, 1, cr);
+	}
+
 	/*
 	 * clget() calls clnt_tli_kinit() which clears the xid, so we
 	 * are guaranteed to reprocess the retry as a new request.
@@ -1281,6 +1290,8 @@
 		if (mi->mi_flags & MI4_SHUTDOWN) {
 			mutex_exit(&mi->mi_lock);
 			clfree4(client, ch, nfscl);
+			if (cred_cloned)
+				crfree(cr);
 			return (EIO);
 		}
 		mutex_exit(&mi->mi_lock);
@@ -1288,6 +1299,8 @@
 		if ((mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED) &&
 		    (!is_recov || !firstcall)) {
 			clfree4(client, ch, nfscl);
+			if (cred_cloned)
+				crfree(cr);
 			return (EIO);
 		}
 
@@ -1297,6 +1310,8 @@
 			    !is_recov || !firstcall) {
 				mutex_exit(&mi->mi_lock);
 				clfree4(client, ch, nfscl);
+				if (cred_cloned)
+					crfree(cr);
 				return (EIO);
 			}
 			mutex_exit(&mi->mi_lock);
@@ -1391,6 +1406,8 @@
 				mi->mi_flags |= MI4_TIMEDOUT;
 				mutex_exit(&mi->mi_lock);
 				clfree4(client, ch, nfscl);
+				if (cred_cloned)
+					crfree(cr);
 				return (EIO);
 			}
 
@@ -1404,6 +1421,8 @@
 			if (mi->mi_vers == 4 && FAILOVER_MOUNT4(mi) &&
 			    (error = try_failover(status)) != 0) {
 				clfree4(client, ch, nfscl);
+				if (cred_cloned)
+					crfree(cr);
 				*rpc_statusp = status;
 				return (error);
 			}
@@ -1526,6 +1545,8 @@
 	}
 
 	clfree4(client, ch, nfscl);
+	if (cred_cloned)
+		crfree(cr);
 
 	ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0);
 
--- a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -57,6 +57,8 @@
 #include <sys/netconfig.h>
 #include <sys/dnlc.h>
 #include <sys/list.h>
+#include <sys/mntent.h>
+#include <sys/tsol/label.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -332,6 +334,7 @@
 	char *userbufptr;
 	zone_t *zone = nfs_zone();
 	nfs4_error_t n4e;
+	zone_t *mntzone = NULL;
 
 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
 		return (EPERM);
@@ -725,22 +728,34 @@
 	/*
 	 * Determine the zone we're being mounted into.
 	 */
+	zone_hold(mntzone = zone);		/* start with this assumption */
 	if (getzoneid() == GLOBAL_ZONEID) {
-		zone_t *mntzone;
-
+		zone_rele(mntzone);
 		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 		ASSERT(mntzone != NULL);
-		zone_rele(mntzone);
 		if (mntzone != zone) {
 			error = EBUSY;
 			goto errout;
 		}
 	}
 
+	if (is_system_labeled()) {
+		error = nfs_mount_label_policy(vfsp, &svp->sv_addr,
+		    svp->sv_knconf, cr);
+
+		if (error > 0)
+			goto errout;
+
+		if (error == -1) {
+			/* change mount to read-only to prevent write-down */
+			vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+		}
+	}
+
 	/*
 	 * Stop the mount from going any further if the zone is going away.
 	 */
-	if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
+	if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
 		error = EBUSY;
 		goto errout;
 	}
@@ -749,7 +764,7 @@
 	 * Get root vnode.
 	 */
 proceed:
-	error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, zone);
+	error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone);
 
 	if (error)
 		goto errout;
@@ -792,10 +807,12 @@
 			/*
 			 * In this error path we need to sfh4_rele() before
 			 * we free the mntinfo4_t as sfh4_rele() has a
-			 * dependancy on mi_fh_lock.
+			 * dependency on mi_fh_lock.
 			 */
-			if (rtvp != NULL)
+			if (rtvp != NULL) {
 				VN_RELE(rtvp);
+				rtvp = NULL;
+			}
 			if (mi->mi_io_kstats) {
 				kstat_delete(mi->mi_io_kstats);
 				mi->mi_io_kstats = NULL;
@@ -809,6 +826,8 @@
 				mi->mi_recov_ksp = NULL;
 			}
 			nfs_free_mi4(mi);
+			if (mntzone != NULL)
+				zone_rele(mntzone);
 			return (error);
 		}
 		sv4_free(svp_head);
@@ -817,6 +836,9 @@
 	if (rtvp != NULL)
 		VN_RELE(rtvp);
 
+	if (mntzone != NULL)
+		zone_rele(mntzone);
+
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
@@ -32,7 +31,7 @@
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/systm.h>
-#include <sys/cred.h>
+#include <sys/cred_impl.h>
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/time.h>
@@ -61,6 +60,10 @@
 #include <sys/callb.h>
 #include <sys/atomic.h>
 #include <sys/list.h>
+#include <sys/tsol/tnet.h>
+#include <sys/priv.h>
+
+#include <inet/ip6.h>
 
 #include <rpc/types.h>
 #include <rpc/xdr.h>
@@ -279,6 +282,11 @@
 extern void sec_clnt_freeinfo(struct sec_data *);
 
 /*
+ * used in mount policy
+ */
+extern ts_label_t *getflabel_cipso(vfs_t *);
+
+/*
  * EIO or EINTR are not recoverable errors.
  */
 #define	IS_RECOVERABLE_ERROR(error)	!((error == EINTR) || (error == EIO))
@@ -914,17 +922,19 @@
 
 static int
 rfscall(mntinfo_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp,
-    xdrproc_t xdrres, caddr_t resp, cred_t *cr, int *douprintf,
+    xdrproc_t xdrres, caddr_t resp, cred_t *icr, int *douprintf,
     enum clnt_stat *rpc_status, int flags, failinfo_t *fi)
 {
 	CLIENT *client;
 	struct chtab *ch;
+	cred_t *cr = icr;
 	enum clnt_stat status;
 	struct rpc_err rpcerr;
 	struct timeval wait;
 	int timeo;		/* in units of hz */
 	int my_rsize, my_wsize;
 	bool_t tryagain;
+	bool_t cred_cloned = FALSE;
 	k_sigset_t smask;
 	servinfo_t *svp;
 	struct nfs_clnt *nfscl;
@@ -1026,6 +1036,13 @@
 		}
 	}
 
+	/* For TSOL, use a new cred which has net_mac_aware flag */
+	if (!cred_cloned && is_system_labeled()) {
+		cred_cloned = TRUE;
+		cr = crdup(icr);
+		(void) setpflags(NET_MAC_AWARE, 1, cr);
+	}
+
 	/*
 	 * clget() calls clnt_tli_kinit() which clears the xid, so we
 	 * are guaranteed to reprocess the retry as a new request.
@@ -1252,6 +1269,8 @@
 				 * the transfer size changed.
 				 */
 				clfree_impl(client, ch, nfscl);
+				if (cred_cloned)
+					crfree(cr);
 				return (ENFS_TRYAGAIN);
 			}
 		}
@@ -1348,6 +1367,8 @@
 	}
 
 	clfree_impl(client, ch, nfscl);
+	if (cred_cloned)
+		crfree(cr);
 
 	ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0);
 
@@ -1449,11 +1470,13 @@
 
 static int
 aclcall(mntinfo_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp,
-    xdrproc_t xdrres, caddr_t resp, cred_t *cr, int *douprintf,
+    xdrproc_t xdrres, caddr_t resp, cred_t *icr, int *douprintf,
     int flags, failinfo_t *fi)
 {
 	CLIENT *client;
 	struct chtab *ch;
+	cred_t *cr = icr;
+	bool_t cred_cloned = FALSE;
 	enum clnt_stat status;
 	struct rpc_err rpcerr;
 	struct timeval wait;
@@ -1562,6 +1585,13 @@
 		}
 	}
 
+	/* For TSOL, use a new cred which has net_mac_aware flag */
+	if (!cred_cloned && is_system_labeled()) {
+		cred_cloned = TRUE;
+		cr = crdup(icr);
+		(void) setpflags(NET_MAC_AWARE, 1, cr);
+	}
+
 	/*
 	 * acl_clget() calls clnt_tli_kinit() which clears the xid, so we
 	 * are guaranteed to reprocess the retry as a new request.
@@ -1581,8 +1611,11 @@
 			goto failoverretry;
 		}
 	}
-	if (rpcerr.re_errno != 0)
+	if (rpcerr.re_errno != 0) {
+		if (cred_cloned)
+			crfree(cr);
 		return (rpcerr.re_errno);
+	}
 
 	if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD ||
 	    svp->sv_knconf->knc_semantics == NC_TPI_COTS) {
@@ -1823,6 +1856,8 @@
 				 * the transfer size changed.
 				 */
 				clfree_impl(client, ch, nfscl);
+				if (cred_cloned)
+					crfree(cr);
 				return (ENFS_TRYAGAIN);
 			}
 #endif
@@ -1921,6 +1956,8 @@
 	}
 
 	clfree_impl(client, ch, nfscl);
+	if (cred_cloned)
+		crfree(cr);
 
 	ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0);
 
@@ -4972,3 +5009,111 @@
 {
 	return (nfs_global_client_only != 0 ? GLOBAL_ZONEID : getzoneid());
 }
+
+/*
+ * nfs_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
+ */
+int
+nfs_mount_label_policy(vfs_t *vfsp, struct netbuf *addr,
+    struct knetconfig *knconf, cred_t *cr)
+{
+	int		addr_type;
+	void		*ipaddr;
+	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);
+
+	if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
+		addr_type = IPV4_VERSION;
+		ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
+	} else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
+		addr_type = IPV6_VERSION;
+		ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
+	} else {
+		retv = 0;
+		goto out;
+	}
+
+	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 != SUN_CIPSO) &&
+	    (tp->tpc_tp.host_type != UNLABELED))
+		goto rel_tpc;			/* invalid hosttype */
+
+	if (tp->tpc_tp.host_type == SUN_CIPSO) {
+		tsl = getflabel_cipso(vfsp);
+		if (tsl == NULL)
+			goto rel_tpc;		/* error getting server lbl */
+
+		server_sl = label2bslabel(tsl);
+	} else {	/* UNLABELED */
+		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:
+	TPC_RELE(tp);
+out:
+	if (mntzone)
+		zone_rele(mntzone);
+	label_rele(zlabel);
+	return (retv);
+}
--- a/usr/src/uts/common/fs/nfs/nfs_vfsops.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs_vfsops.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
@@ -55,6 +54,8 @@
 #include <sys/class.h>
 #include <sys/socket.h>
 #include <sys/netconfig.h>
+#include <sys/mntent.h>
+#include <sys/tsol/label.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -223,6 +224,7 @@
 	int flags, addr_type;
 	char *p, *pf;
 	zone_t *zone = nfs_zone();
+	zone_t *mntzone = NULL;
 
 	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 		return (error);
@@ -670,22 +672,34 @@
 	/*
 	 * Determine the zone we're being mounted into.
 	 */
+	zone_hold(mntzone = zone);		/* start with this assumption */
 	if (getzoneid() == GLOBAL_ZONEID) {
-		zone_t *mntzone;
-
+		zone_rele(mntzone);
 		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 		ASSERT(mntzone != NULL);
-		zone_rele(mntzone);
 		if (mntzone != zone) {
 			error = EBUSY;
 			goto errout;
 		}
 	}
 
+	if (is_system_labeled()) {
+		error = nfs_mount_label_policy(vfsp, &svp->sv_addr,
+		    svp->sv_knconf, cr);
+
+		if (error > 0)
+			goto errout;
+
+		if (error == -1) {
+			/* change mount to read-only to prevent write-down */
+			vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+		}
+	}
+
 	/*
 	 * Stop the mount from going any further if the zone is going away.
 	 */
-	if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
+	if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
 		error = EBUSY;
 		goto errout;
 	}
@@ -694,7 +708,7 @@
 	 * Get root vnode.
 	 */
 proceed:
-	error = nfsrootvp(&rtvp, vfsp, svp_head, flags, cr, zone);
+	error = nfsrootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone);
 
 	if (error)
 		goto errout;
@@ -739,6 +753,9 @@
 	if (rtvp != NULL)
 		VN_RELE(rtvp);
 
+	if (mntzone != NULL)
+		zone_rele(mntzone);
+
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/sockfs/socksyscalls.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/fs/sockfs/socksyscalls.c	Fri Mar 24 12:29:20 2006 -0800
@@ -41,9 +41,7 @@
 #include <sys/errno.h>
 #include <sys/time.h>
 #include <sys/file.h>
-#include <sys/open.h>
 #include <sys/user.h>
-#include <sys/termios.h>
 #include <sys/stream.h>
 #include <sys/strsubr.h>
 #include <sys/strsun.h>
@@ -56,15 +54,11 @@
 
 #include <sys/socket.h>
 #include <sys/socketvar.h>
-#include <netinet/in.h>
-#include <sys/un.h>
-#include <inet/nca/ncadoorhdr.h>
 
 #include <sys/isa_defs.h>
 #include <sys/inttypes.h>
 #include <sys/systm.h>
 #include <sys/cpuvar.h>
-#include <sys/atomic.h>
 #include <sys/filio.h>
 #include <sys/sendfile.h>
 #include <sys/ddi.h>
--- a/usr/src/uts/common/inet/ip.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip.h	Fri Mar 24 12:29:20 2006 -0800
@@ -51,6 +51,7 @@
 #include <sys/avl.h>
 #include <sys/vmem.h>
 #include <sys/squeue.h>
+#include <net/route.h>
 #include <sys/systm.h>
 #include <sys/multidata.h>
 
@@ -124,6 +125,8 @@
 #define	IP_SIMPLE_HDR_LENGTH		20
 #define	IP_MAX_HDR_LENGTH		60
 
+#define	IP_MAX_OPT_LENGTH (IP_MAX_HDR_LENGTH-IP_SIMPLE_HDR_LENGTH)
+
 #define	IP_MIN_MTU			(IP_MAX_HDR_LENGTH + 8)	/* 68 bytes */
 
 /*
@@ -134,6 +137,8 @@
 #define	IP_SIMPLE_HDR_VERSION \
 	((IP_VERSION << 4) | IP_SIMPLE_HDR_LENGTH_IN_WORDS)
 
+#define	UDPH_SIZE			8
+
 /*
  * Constants and type definitions to support IP IOCTL commands
  */
@@ -2074,6 +2079,104 @@
 } ipndp_t;
 
 /*
+ * The kernel stores security attributes of all gateways in a database made
+ * up of one or more tsol_gcdb_t elements.  Each tsol_gcdb_t contains the
+ * security-related credentials of the gateway.  More than one gateways may
+ * share entries in the database.
+ *
+ * The tsol_gc_t structure represents the gateway to credential association,
+ * and refers to an entry in the database.  One or more tsol_gc_t entities are
+ * grouped together to form one or more tsol_gcgrp_t, each representing the
+ * list of security attributes specific to the gateway.  A gateway may be
+ * associated with at most one credentials group.
+ */
+struct tsol_gcgrp_s;
+
+extern uchar_t	ip6opt_ls;	/* TX IPv6 enabler */
+
+/*
+ * Gateway security credential record.
+ */
+typedef struct tsol_gcdb_s {
+	uint_t		gcdb_refcnt;	/* reference count */
+	struct rtsa_s	gcdb_attr;	/* security attributes */
+#define	gcdb_mask	gcdb_attr.rtsa_mask
+#define	gcdb_doi	gcdb_attr.rtsa_doi
+#define	gcdb_slrange	gcdb_attr.rtsa_slrange
+} tsol_gcdb_t;
+
+/*
+ * Gateway to credential association.
+ */
+typedef struct tsol_gc_s {
+	uint_t		gc_refcnt;	/* reference count */
+	struct tsol_gcgrp_s *gc_grp;	/* pointer to group */
+	struct tsol_gc_s *gc_prev;	/* previous in list */
+	struct tsol_gc_s *gc_next;	/* next in list */
+	tsol_gcdb_t	*gc_db;		/* pointer to actual credentials */
+} tsol_gc_t;
+
+/*
+ * Gateway credentials group address.
+ */
+typedef struct tsol_gcgrp_addr_s {
+	int		ga_af;		/* address family */
+	in6_addr_t	ga_addr;	/* IPv4 mapped or IPv6 address */
+} tsol_gcgrp_addr_t;
+
+/*
+ * Gateway credentials group.
+ */
+typedef struct tsol_gcgrp_s {
+	uint_t		gcgrp_refcnt;	/* reference count */
+	krwlock_t	gcgrp_rwlock;	/* lock to protect following */
+	uint_t		gcgrp_count;	/* number of credentials */
+	tsol_gc_t	*gcgrp_head;	/* first credential in list */
+	tsol_gc_t	*gcgrp_tail;	/* last credential in list */
+	tsol_gcgrp_addr_t gcgrp_addr;	/* next-hop gateway address */
+} tsol_gcgrp_t;
+
+extern kmutex_t gcgrp_lock;
+
+#define	GC_REFRELE(p) {				\
+	ASSERT((p)->gc_grp != NULL);		\
+	rw_enter(&(p)->gc_grp->gcgrp_rwlock, RW_WRITER); \
+	ASSERT((p)->gc_refcnt > 0);		\
+	if (--((p)->gc_refcnt) == 0)		\
+		gc_inactive(p);			\
+	else					\
+		rw_exit(&(p)->gc_grp->gcgrp_rwlock); \
+}
+
+#define	GCGRP_REFHOLD(p) {			\
+	mutex_enter(&gcgrp_lock);		\
+	++((p)->gcgrp_refcnt);			\
+	ASSERT((p)->gcgrp_refcnt != 0);		\
+	mutex_exit(&gcgrp_lock);		\
+}
+
+#define	GCGRP_REFRELE(p) {			\
+	mutex_enter(&gcgrp_lock);		\
+	ASSERT((p)->gcgrp_refcnt > 0);		\
+	if (--((p)->gcgrp_refcnt) == 0)		\
+		gcgrp_inactive(p);		\
+	ASSERT(MUTEX_HELD(&gcgrp_lock));	\
+	mutex_exit(&gcgrp_lock);		\
+}
+
+/*
+ * IRE gateway security attributes structure, pointed to by tsol_ire_gw_secattr
+ */
+struct tsol_tnrhc;
+
+typedef struct tsol_ire_gw_secattr_s {
+	kmutex_t	igsa_lock;	/* lock to protect following */
+	struct tsol_tnrhc *igsa_rhc;	/* host entry for gateway */
+	tsol_gc_t	*igsa_gc;	/* for prefix IREs */
+	tsol_gcgrp_t	*igsa_gcgrp;	/* for cache IREs */
+} tsol_ire_gw_secattr_t;
+
+/*
  * Following are the macros to increment/decrement the reference
  * count of the IREs and IRBs (ire bucket).
  *
@@ -2306,6 +2409,7 @@
 	clock_t		ire_last_used_time;	/* Last used time */
 	struct ire_s 	*ire_fastpath;	/* Pointer to next ire in fastpath */
 	zoneid_t	ire_zoneid;	/* for local address discrimination */
+	tsol_ire_gw_secattr_t *ire_gw_secattr; /* gateway security attributes */
 #ifdef IRE_DEBUG
 	th_trace_t	*ire_trace[IP_TR_HASH_MAX];
 	boolean_t	ire_trace_disable;	/* True when alloc fails */
@@ -2433,6 +2537,8 @@
 };
 typedef struct ip6_pkt_s ip6_pkt_t;
 
+extern void ip6_pkt_free(ip6_pkt_t *);	/* free storage inside ip6_pkt_t */
+
 /*
  * This structure is used to convey information from IP and the ULP.
  * Currently used for the IP_RECVSLLA and IP_RECVIF options. The
@@ -2447,7 +2553,7 @@
 } in_pktinfo_t;
 
 /*
- * flags to tell UDP what IP is sending
+ * flags to tell UDP what IP is sending; in_pkt_flags
  */
 #define	IPF_RECVIF	0x01	/* inbound interface index */
 #define	IPF_RECVSLLA	0x02	/* source link layer address */
@@ -2832,6 +2938,7 @@
 
 extern uint8_t	ipoptp_next(ipoptp_t *);
 extern uint8_t	ipoptp_first(ipoptp_t *, ipha_t *);
+extern int	ip_opt_get_user(const ipha_t *, uchar_t *);
 extern ill_t	*ip_grab_attach_ill(ill_t *, mblk_t *, int, boolean_t);
 extern ire_t	*conn_set_outgoing_ill(conn_t *, ire_t *, ill_t **);
 extern int	ipsec_req_from_conn(conn_t *, ipsec_req_t *, int);
@@ -2844,6 +2951,12 @@
 extern void	ip_ioctl_finish(queue_t *, mblk_t *, int, int, ipif_t *,
     ipsq_t *);
 
+extern boolean_t ip_cmpbuf(const void *, uint_t, boolean_t, const void *,
+    uint_t);
+extern boolean_t ip_allocbuf(void **, uint_t *, boolean_t, const void *,
+    uint_t);
+extern void	ip_savebuf(void **, uint_t *, boolean_t, const void *, uint_t);
+
 extern boolean_t	ipsq_pending_mp_cleanup(ill_t *, conn_t *);
 extern void	conn_ioctl_cleanup(conn_t *);
 extern ill_t	*conn_get_held_ill(conn_t *, ill_t **, int *);
@@ -2862,6 +2975,9 @@
 			uint_t);
 extern mblk_t	*ip_unbind(queue_t *, mblk_t *);
 
+extern void tnet_init(void);
+extern void tnet_fini(void);
+
 /* Hooks for CGTP (multirt routes) filtering module */
 #define	CGTP_FILTER_REV_1	1
 #define	CGTP_FILTER_REV_2	2
@@ -3004,6 +3120,17 @@
 };
 
 /*
+ * This message is sent by an upper-layer protocol to tell IP that it knows all
+ * about labels and will construct them itself.  IP takes the slow path and
+ * recomputes the label on every packet when this isn't true.
+ */
+#define	IP_ULP_OUT_LABELED		(('O' << 8) + 'L')
+typedef struct out_labeled_s {
+	uint32_t	out_labeled_type;	/* OUT_LABELED */
+	queue_t		*out_qnext;		/* intermediate detection */
+} out_labeled_t;
+
+/*
  * IP squeues exports
  */
 extern int 		ip_squeue_profile;
--- a/usr/src/uts/common/inet/ip/icmp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/icmp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -37,10 +37,12 @@
 #include <sys/timod.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
+#include <sys/strsubr.h>
 #include <sys/cmn_err.h>
 #include <sys/debug.h>
 #include <sys/kmem.h>
 #include <sys/policy.h>
+#include <sys/priv.h>
 #include <sys/zone.h>
 #include <sys/time.h>
 
@@ -58,7 +60,6 @@
 #include <inet/common.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
-#include <inet/ip_ire.h>
 #include <inet/mi.h>
 #include <inet/nd.h>
 #include <inet/optcom.h>
@@ -72,6 +73,9 @@
 #include <inet/ipsec_info.h>
 #include <inet/ipclassifier.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+
 #define	ICMP6 "icmp6"
 major_t	ICMP6_MAJ;
 
@@ -133,8 +137,6 @@
 static boolean_t icmp_param_register(icmpparam_t *icmppa, int cnt);
 static int	icmp_param_set(queue_t *q, mblk_t *mp, char *value,
 		    caddr_t cp, cred_t *cr);
-static int	icmp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky,
-		    uchar_t **optbufp, uint_t *optlenp);
 static void	icmp_rput(queue_t *q, mblk_t *mp);
 static void	icmp_rput_bind_ack(queue_t *q, mblk_t *mp);
 static int	icmp_snmp_get(queue_t *q, mblk_t *mpctl);
@@ -614,6 +616,7 @@
 	linkb(mp1, mp);
 	linkb(mp1, mp2);
 
+	mblk_setcred(mp1, icmp->icmp_credp);
 	putnext(q, mp1);
 }
 
@@ -623,6 +626,10 @@
 	icmp_t	*icmp = (icmp_t *)q->q_ptr;
 	int	i1;
 
+	/* tell IP that if we're not here, he can't trust labels */
+	if (is_system_labeled())
+		putnext(WR(q), icmp->icmp_delabel);
+
 	qprocsoff(q);
 
 	/* If there are any options associated with the stream, free them. */
@@ -639,28 +646,8 @@
 		icmp->icmp_sticky_hdrs = NULL;
 		icmp->icmp_sticky_hdrs_len = 0;
 	}
-	if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) {
-		kmem_free(icmp->icmp_sticky_ipp.ipp_hopopts,
-		    icmp->icmp_sticky_ipp.ipp_hopoptslen);
-	}
-	if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) {
-		kmem_free(icmp->icmp_sticky_ipp.ipp_rtdstopts,
-		    icmp->icmp_sticky_ipp.ipp_rtdstoptslen);
-	}
-	if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTHDR) {
-		kmem_free(icmp->icmp_sticky_ipp.ipp_rthdr,
-		    icmp->icmp_sticky_ipp.ipp_rthdrlen);
-	}
-	if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) {
-		kmem_free(icmp->icmp_sticky_ipp.ipp_dstopts,
-		    icmp->icmp_sticky_ipp.ipp_dstoptslen);
-	}
-	if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_PATHMTU) {
-		kmem_free(icmp->icmp_sticky_ipp.ipp_pathmtu,
-		    icmp->icmp_sticky_ipp.ipp_pathmtulen);
-	}
-	icmp->icmp_sticky_ipp.ipp_fields &=
-	    ~(IPPF_HOPOPTS|IPPF_RTDSTOPTS|IPPF_RTHDR|IPPF_DSTOPTS);
+
+	ip6_pkt_free(&icmp->icmp_sticky_ipp);
 
 	crfree(icmp->icmp_credp);
 
@@ -1295,6 +1282,37 @@
 	return (mp);
 }
 
+/* ARGSUSED */
+static void
+dummy_func(void *arg)
+{
+}
+
+static mblk_t *
+alloc_wait(queue_t *q, size_t len, int pri, int *errp)
+{
+	mblk_t *mp;
+	bufcall_id_t id;
+	int retv;
+
+	while ((mp = allocb(len, pri)) == NULL) {
+		id = qbufcall(q, len, pri, dummy_func, NULL);
+		if (id == 0) {
+			*errp = ENOMEM;
+			break;
+		}
+		retv = qwait_sig(q);
+		qunbufcall(q, id);
+		if (retv == 0) {
+			*errp = EINTR;
+			break;
+		}
+	}
+	if (mp != NULL)
+		mp->b_wptr += len;
+	return (mp);
+}
+
 /*
  * This is the open routine for icmp.  It allocates a icmp_t structure for
  * the stream and, on the first open of the module, creates an ND table.
@@ -1304,6 +1322,8 @@
 {
 	int	err;
 	icmp_t	*icmp;
+	mblk_t	*mp;
+	out_labeled_t *olp;
 
 	/* If the stream is already open, return immediately. */
 	if (q->q_ptr != NULL)
@@ -1326,7 +1346,7 @@
 	 */
 	err = mi_open_comm(&icmp_g_head, sizeof (icmp_t), q, devp,
 	    flag, sflag, credp);
-	if (err)
+	if (err != 0)
 		return (err);
 
 	/*
@@ -1345,6 +1365,13 @@
 	icmp->icmp_credp = credp;
 	crhold(credp);
 
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		icmp->icmp_mac_exempt = B_TRUE;
+
 	icmp->icmp_zoneid = getzoneid();
 
 	if (getmajor(*devp) == (major_t)ICMP6_MAJ) {
@@ -1386,19 +1413,43 @@
 
 	if (icmp->icmp_family == AF_INET6) {
 		/* Build initial header template for transmit */
-		int error;
-
-		error = icmp_build_hdrs(q, icmp);
-		if (error != 0) {
-			(void) icmp_close(q);
-			return (error);
-		}
+		err = icmp_build_hdrs(q, icmp);
+		if (err != 0)
+			goto open_error;
 	}
 	/* Set the Stream head write offset. */
 	(void) mi_set_sth_wroff(q, icmp->icmp_max_hdr_len + icmp_wroff_extra);
 	(void) mi_set_sth_hiwat(q, q->q_hiwat);
 
+	if (is_system_labeled()) {
+		/* notify IP that we know about labeling */
+		mp = alloc_wait(q, sizeof (*olp), BPRI_MED, &err);
+		if (mp == NULL)
+			goto open_error;
+		mp->b_datap->db_type = M_CTL;
+		olp = (out_labeled_t *)mp->b_rptr;
+		olp->out_labeled_type = IP_ULP_OUT_LABELED;
+		olp->out_qnext = WR(q)->q_next;
+		putnext(WR(q), mp);
+
+		/* save off a copy for closing */
+		mp = alloc_wait(q, sizeof (*olp), BPRI_MED, &err);
+		if (mp == NULL)
+			goto open_error;
+		mp->b_datap->db_type = M_CTL;
+		olp = (out_labeled_t *)mp->b_rptr;
+		olp->out_labeled_type = IP_ULP_OUT_LABELED;
+		olp->out_qnext = NULL;
+		icmp->icmp_delabel = mp;
+	}
+
 	return (0);
+
+open_error:
+	qprocsoff(q);
+	crfree(credp);
+	(void) mi_close_comm(&icmp_g_head, q);
+	return (err);
 }
 
 /*
@@ -1512,6 +1563,9 @@
 		case SO_TIMESTAMP:
 			*i1 = icmp->icmp_timestamp;
 			break;
+		case SO_MAC_EXEMPT:
+			*i1 = icmp->icmp_mac_exempt;
+			break;
 		/*
 		 * Following three not meaningful for icmp
 		 * Action is same as "default" to which we fallthrough
@@ -1711,8 +1765,17 @@
 		case IPV6_HOPOPTS:
 			if (!(ipp->ipp_fields & IPPF_HOPOPTS))
 				return (0);
-			bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen);
-			return (ipp->ipp_hopoptslen);
+			if (ipp->ipp_hopoptslen <= icmp->icmp_label_len_v6)
+				return (0);
+			bcopy((char *)ipp->ipp_hopopts +
+			    icmp->icmp_label_len_v6, ptr,
+			    ipp->ipp_hopoptslen - icmp->icmp_label_len_v6);
+			if (icmp->icmp_label_len_v6 > 0) {
+				ptr[0] = ((char *)ipp->ipp_hopopts)[0];
+				ptr[1] = (ipp->ipp_hopoptslen -
+				    icmp->icmp_label_len_v6 + 7) / 8 - 1;
+			}
+			return (ipp->ipp_hopoptslen - icmp->icmp_label_len_v6);
 		case IPV6_RTHDRDSTOPTS:
 			if (!(ipp->ipp_fields & IPPF_RTDSTOPTS))
 				return (0);
@@ -1966,6 +2029,13 @@
 				icmp->icmp_timestamp = onoff;
 			}
 			break;
+		case SO_MAC_EXEMPT:
+			if (secpolicy_net_mac_aware(cr) != 0 ||
+			    icmp->icmp_state != TS_UNBND)
+				return (EACCES);
+			if (!checkonly)
+				icmp->icmp_mac_exempt = onoff;
+			break;
 		/*
 		 * Following three not meaningful for icmp
 		 * Action is same as "default" so we keep them
@@ -1991,27 +2061,21 @@
 		case IP_OPTIONS:
 		case T_IP_OPTIONS:
 			/* Save options for use by IP. */
-			if (inlen & 0x3) {
+			if ((inlen & 0x3) ||
+			    inlen + icmp->icmp_label_len > IP_MAX_OPT_LENGTH) {
 				*outlenp = 0;
 				return (EINVAL);
 			}
 			if (checkonly)
 				break;
 
-			if (icmp->icmp_ip_snd_options) {
-				mi_free((char *)icmp->icmp_ip_snd_options);
-				icmp->icmp_ip_snd_options_len = 0;
-				icmp->icmp_ip_snd_options = NULL;
+			if (!tsol_option_set(&icmp->icmp_ip_snd_options,
+			    &icmp->icmp_ip_snd_options_len,
+			    icmp->icmp_label_len, invalp, inlen)) {
+				*outlenp = 0;
+				return (ENOMEM);
 			}
-			if (inlen) {
-				icmp->icmp_ip_snd_options =
-				    (uchar_t *)mi_alloc(inlen, BPRI_HI);
-				if (icmp->icmp_ip_snd_options) {
-					bcopy(invalp,
-					    icmp->icmp_ip_snd_options, inlen);
-					icmp->icmp_ip_snd_options_len = inlen;
-				}
-			}
+
 			icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH +
 			    icmp->icmp_ip_snd_options_len;
 			(void) mi_set_sth_wroff(RD(q), icmp->icmp_max_hdr_len +
@@ -2417,22 +2481,16 @@
 
 			if (checkonly)
 				break;
-			if (inlen == 0) {
-				if (sticky &&
-				    (ipp->ipp_fields & IPPF_HOPOPTS) != 0) {
-					kmem_free(ipp->ipp_hopopts,
-					    ipp->ipp_hopoptslen);
-					ipp->ipp_hopopts = NULL;
-					ipp->ipp_hopoptslen = 0;
-				}
+			error = optcom_pkt_set(invalp, inlen, sticky,
+			    (uchar_t **)&ipp->ipp_hopopts,
+			    &ipp->ipp_hopoptslen,
+			    sticky ? icmp->icmp_label_len_v6 : 0);
+			if (error != 0)
+				return (error);
+			if (ipp->ipp_hopoptslen == 0) {
 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_HOPOPTS;
 			} else {
-				error = icmp_pkt_set(invalp, inlen, sticky,
-				    (uchar_t **)&ipp->ipp_hopopts,
-				    &ipp->ipp_hopoptslen);
-				if (error != 0)
-					return (error);
 				ipp->ipp_fields |= IPPF_HOPOPTS;
 			}
 			if (sticky) {
@@ -2467,9 +2525,9 @@
 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_RTDSTOPTS;
 			} else {
-				error = icmp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_rtdstopts,
-				    &ipp->ipp_rtdstoptslen);
+				    &ipp->ipp_rtdstoptslen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
@@ -2506,9 +2564,9 @@
 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_DSTOPTS;
 			} else {
-				error = icmp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_dstopts,
-				    &ipp->ipp_dstoptslen);
+				    &ipp->ipp_dstoptslen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_DSTOPTS;
@@ -2545,9 +2603,9 @@
 				ipp->ipp_fields &= ~IPPF_RTHDR;
 				ipp->ipp_sticky_ignored |= IPPF_RTHDR;
 			} else {
-				error = icmp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_rthdr,
-				    &ipp->ipp_rthdrlen);
+				    &ipp->ipp_rthdrlen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_RTHDR;
@@ -2733,46 +2791,6 @@
 }
 
 /*
- * Set optbuf and optlen for the option.
- * If sticky is set allocate memory (if not already present).
- * Otherwise just point optbuf and optlen at invalp and inlen.
- * Returns failure if memory can not be allocated.
- */
-static int
-icmp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky,
-    uchar_t **optbufp, uint_t *optlenp)
-{
-	uchar_t *optbuf;
-
-	if (!sticky) {
-		*optbufp = invalp;
-		*optlenp = inlen;
-		return (0);
-	}
-	if (inlen == *optlenp) {
-		/* Unchanged length - no need to realocate */
-		bcopy(invalp, *optbufp, inlen);
-		return (0);
-	}
-	if (inlen != 0) {
-		/* Allocate new buffer before free */
-		optbuf = kmem_alloc(inlen, KM_NOSLEEP);
-		if (optbuf == NULL)
-			return (ENOMEM);
-	} else {
-		optbuf = NULL;
-	}
-	/* Free old buffer */
-	if (*optlenp != 0)
-		kmem_free(*optbufp, *optlenp);
-
-	bcopy(invalp, optbuf, inlen);
-	*optbufp = optbuf;
-	*optlenp = inlen;
-	return (0);
-}
-
-/*
  * This routine retrieves the value of an ND variable in a icmpparam_t
  * structure.  It is called through nd_getset when a user reads the
  * variable.
@@ -2857,6 +2875,7 @@
 	mblk_t			*options_mp = NULL;
 	uint_t			icmp_opt = 0;
 	boolean_t		icmp_ipv6_recvhoplimit = B_FALSE;
+	uint_t			hopstrip;
 
 	icmp = (icmp_t *)q->q_ptr;
 	if (icmp->icmp_restricted) {
@@ -3186,6 +3205,7 @@
 
 	/* Initialize */
 	ipp.ipp_fields = 0;
+	hopstrip = 0;
 
 	ip6h = (ip6_t *)rptr;
 	/*
@@ -3214,6 +3234,52 @@
 			ip6h = (ip6_t *)rptr;
 		}
 		hdr_len = ip_find_hdr_v6(mp, ip6h, &ipp, &nexthdr);
+
+		/*
+		 * We need to lie a bit to the user because users inside
+		 * labeled compartments should not see their own labels.  We
+		 * assume that in all other respects IP has checked the label,
+		 * and that the label is always first among the options.  (If
+		 * it's not first, then this code won't see it, and the option
+		 * will be passed along to the user.)
+		 *
+		 * If we had multilevel ICMP sockets, then the following code
+		 * should be skipped for them to allow the user to see the
+		 * label.
+		 *
+		 * Alignment restrictions in the definition of IP options
+		 * (namely, the requirement that the 4-octet DOI goes on a
+		 * 4-octet boundary) mean that we know exactly where the option
+		 * should start, but we're lenient for other hosts.
+		 *
+		 * Note that there are no multilevel ICMP or raw IP sockets
+		 * yet, thus nobody ever sees the IP6OPT_LS option.
+		 */
+		if ((ipp.ipp_fields & IPPF_HOPOPTS) &&
+		    ipp.ipp_hopoptslen > 5 && is_system_labeled()) {
+			const uchar_t *ucp =
+			    (const uchar_t *)ipp.ipp_hopopts + 2;
+			int remlen = ipp.ipp_hopoptslen - 2;
+
+			while (remlen > 0) {
+				if (*ucp == IP6OPT_PAD1) {
+					remlen--;
+					ucp++;
+				} else if (*ucp == IP6OPT_PADN) {
+					remlen -= ucp[1] + 2;
+					ucp += ucp[1] + 2;
+				} else if (*ucp == ip6opt_ls) {
+					hopstrip = (ucp -
+					    (const uchar_t *)ipp.ipp_hopopts) +
+					    ucp[1] + 2;
+					hopstrip = (hopstrip + 7) & ~7;
+					break;
+				} else {
+					/* label option must be first */
+					break;
+				}
+			}
+		}
 	} else {
 		hdr_len = IPV6_HDR_LEN;
 		ip6i = NULL;
@@ -3293,9 +3359,10 @@
 	if (ipp.ipp_fields & (IPPF_HOPOPTS|IPPF_DSTOPTS|IPPF_RTDSTOPTS|
 	    IPPF_RTHDR|IPPF_IFINDEX)) {
 		if (icmp->icmp_ipv6_recvhopopts &&
-		    (ipp.ipp_fields & IPPF_HOPOPTS)) {
+		    (ipp.ipp_fields & IPPF_HOPOPTS) &&
+		    ipp.ipp_hopoptslen > hopstrip) {
 			udi_size += sizeof (struct T_opthdr) +
-			    ipp.ipp_hopoptslen;
+			    ipp.ipp_hopoptslen - hopstrip;
 			icmp_opt |= IPPF_HOPOPTS;
 		}
 		if ((icmp->icmp_ipv6_recvdstopts ||
@@ -3425,12 +3492,18 @@
 			toh->level = IPPROTO_IPV6;
 			toh->name = IPV6_HOPOPTS;
 			toh->len = sizeof (struct T_opthdr) +
-			    ipp.ipp_hopoptslen;
+			    ipp.ipp_hopoptslen - hopstrip;
 			toh->status = 0;
 			dstopt += sizeof (struct T_opthdr);
-			bcopy(ipp.ipp_hopopts, dstopt,
-			    ipp.ipp_hopoptslen);
-			dstopt += ipp.ipp_hopoptslen;
+			bcopy((char *)ipp.ipp_hopopts + hopstrip, dstopt,
+			    ipp.ipp_hopoptslen - hopstrip);
+			if (hopstrip > 0) {
+				/* copy next header value and fake length */
+				dstopt[0] = ((uchar_t *)ipp.ipp_hopopts)[0];
+				dstopt[1] = ((uchar_t *)ipp.ipp_hopopts)[1] -
+				    hopstrip / 8;
+			}
+			dstopt += ipp.ipp_hopoptslen - hopstrip;
 			udi_size -= toh->len;
 		}
 		if (icmp_opt & IPPF_RTDSTOPTS) {
@@ -3850,9 +3923,36 @@
 		 */
 		(void) ip_massage_options(ipha);
 	}
+	mblk_setcred(mp, icmp->icmp_credp);
 	putnext(q, mp);
 }
 
+static boolean_t
+icmp_update_label(queue_t *q, icmp_t *icmp, mblk_t *mp, ipaddr_t dst)
+{
+	int err;
+	uchar_t opt_storage[IP_MAX_OPT_LENGTH];
+
+	err = tsol_compute_label(DB_CREDDEF(mp, icmp->icmp_credp), dst,
+	    opt_storage, icmp->icmp_mac_exempt);
+	if (err == 0) {
+		err = tsol_update_options(&icmp->icmp_ip_snd_options,
+		    &icmp->icmp_ip_snd_options_len, &icmp->icmp_label_len,
+		    opt_storage);
+	}
+	if (err != 0) {
+		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		DTRACE_PROBE4(
+		    tx__ip__log__drop__updatelabel__icmp,
+		    char *, "queue(1) failed to update options(2) on mp(3)",
+		    queue_t *, q, char *, opt_storage, mblk_t *, mp);
+		icmp_ud_err(q, mp, err);
+		return (B_FALSE);
+	}
+	IN6_IPADDR_TO_V4MAPPED(dst, &icmp->icmp_v6lastdst);
+	return (B_TRUE);
+}
+
 /*
  * This routine handles all messages passed downstream.  It either
  * consumes the message or passes it downstream; it never queues a
@@ -3882,6 +3982,27 @@
 	case M_DATA:
 		if (icmp->icmp_hdrincl) {
 			ASSERT(icmp->icmp_ipversion == IPV4_VERSION);
+			ipha = (ipha_t *)mp->b_rptr;
+			if (mp->b_wptr - mp->b_rptr < IP_SIMPLE_HDR_LENGTH) {
+				if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) {
+					BUMP_MIB(&rawip_mib, rawipOutErrors);
+					freemsg(mp);
+					return;
+				}
+				ipha = (ipha_t *)mp->b_rptr;
+			}
+			/*
+			 * If this connection was used for v6 (inconceivable!)
+			 * or if we have a new destination, then it's time to
+			 * figure a new label.
+			 */
+			if (is_system_labeled() &&
+			    (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
+			    V4_PART_OF_V6(icmp->icmp_v6lastdst) !=
+			    ipha->ipha_dst) &&
+			    !icmp_update_label(q, icmp, mp, ipha->ipha_dst)) {
+				return;
+			}
 			icmp_wput_hdrincl(q, mp, icmp);
 			return;
 		}
@@ -3960,6 +4081,9 @@
 		/* Extract and ipaddr */
 		v4dst = sin->sin_addr.s_addr;
 		break;
+
+	default:
+		ASSERT(0);
 	}
 
 	/*
@@ -3983,12 +4107,24 @@
 		 */
 	}
 
+	if (v4dst == INADDR_ANY)
+		v4dst = htonl(INADDR_LOOPBACK);
+
+	/* Check if our saved options are valid; update if not */
+	if (is_system_labeled() &&
+	    (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
+	    V4_PART_OF_V6(icmp->icmp_v6lastdst) != v4dst) &&
+	    !icmp_update_label(q, icmp, mp, v4dst)) {
+		return;
+	}
+
 	/* Protocol 255 contains full IP headers */
 	if (icmp->icmp_hdrincl) {
 		freeb(mp);
 		icmp_wput_hdrincl(q, mp1, icmp);
 		return;
 	}
+
 	/* Add an IP header */
 	ip_hdr_length = IP_SIMPLE_HDR_LENGTH + icmp->icmp_ip_snd_options_len;
 	ipha = (ipha_t *)&mp1->b_rptr[-ip_hdr_length];
@@ -4059,10 +4195,7 @@
 	 * Copy in the destination address from the T_UNITDATA
 	 * request
 	 */
-	if (v4dst == INADDR_ANY)
-		ipha->ipha_dst = htonl(INADDR_LOOPBACK);
-	else
-		ipha->ipha_dst = v4dst;
+	ipha->ipha_dst = v4dst;
 
 	/*
 	 * Set ttl based on IP_MULTICAST_TTL to match IPv6 logic.
@@ -4082,15 +4215,42 @@
 	}
 	freeb(mp);
 	BUMP_MIB(&rawip_mib, rawipOutDatagrams);
+	mblk_setcred(mp1, icmp->icmp_credp);
 	putnext(q, mp1);
 #undef	ipha
 #undef tudr
 }
 
+static boolean_t
+icmp_update_label_v6(queue_t *wq, icmp_t *icmp, mblk_t *mp, in6_addr_t *dst)
+{
+	int err;
+	uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
+
+	err = tsol_compute_label_v6(DB_CREDDEF(mp, icmp->icmp_credp), dst,
+	    opt_storage, icmp->icmp_mac_exempt);
+	if (err == 0) {
+		err = tsol_update_sticky(&icmp->icmp_sticky_ipp,
+		    &icmp->icmp_label_len_v6, opt_storage);
+	}
+	if (err != 0) {
+		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		DTRACE_PROBE4(
+		    tx__ip__log__drop__updatelabel__icmp6,
+		    char *, "queue(1) failed to update options(2) on mp(3)",
+		    queue_t *, wq, char *, opt_storage, mblk_t *, mp);
+		icmp_ud_err(wq, mp, err);
+		return (B_FALSE);
+	}
+
+	icmp->icmp_v6lastdst = *dst;
+	return (B_TRUE);
+}
+
 /*
  * icmp_wput_ipv6():
  * Assumes that icmp_wput did some sanity checking on the destination
- * address.
+ * address, but that the label may not yet be correct.
  */
 void
 icmp_wput_ipv6(queue_t *q, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen)
@@ -4109,6 +4269,7 @@
 	uint_t			option_exists = 0, is_sticky = 0;
 	uint8_t			*cp;
 	uint8_t			*nxthdr_ptr;
+	in6_addr_t		ip6_dst;
 
 	icmp = (icmp_t *)q->q_ptr;
 
@@ -4155,6 +4316,34 @@
 		option_exists |= IPPF_SCOPE_ID;
 	}
 
+	/*
+	 * Compute the destination address
+	 */
+	ip6_dst = sin6->sin6_addr;
+	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+		ip6_dst = ipv6_loopback;
+
+	/*
+	 * If we're not going to the same destination as last time, then
+	 * recompute the label required.  This is done in a separate routine to
+	 * avoid blowing up our stack here.
+	 */
+	if (is_system_labeled() &&
+	    !IN6_ARE_ADDR_EQUAL(&icmp->icmp_v6lastdst, &ip6_dst) &&
+	    !icmp_update_label_v6(q, icmp, mp, &ip6_dst)) {
+		return;
+	}
+
+	/*
+	 * If there's a security label here, then we ignore any options the
+	 * user may try to set.  We keep the peer's label as a hidden sticky
+	 * option.
+	 */
+	if (icmp->icmp_label_len_v6 > 0) {
+		ignore &= ~IPPF_HOPOPTS;
+		ipp->ipp_fields &= ~IPPF_HOPOPTS;
+	}
+
 	if ((icmp->icmp_sticky_ipp.ipp_fields == 0) &&
 	    (ipp->ipp_fields == 0)) {
 		/* No sticky options nor ancillary data. */
@@ -4497,10 +4686,7 @@
 	/*
 	 * Copy in the destination address
 	 */
-	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
-		ip6h->ip6_dst = ipv6_loopback;
-	else
-		ip6h->ip6_dst = sin6->sin6_addr;
+	ip6h->ip6_dst = ip6_dst;
 
 	ip6h->ip6_vcf =
 		(IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) |
@@ -4622,6 +4808,7 @@
 
 	/* We're done. Pass the packet to IP */
 	BUMP_MIB(&rawip_mib, rawipOutDatagrams);
+	mblk_setcred(mp1, icmp->icmp_credp);
 	putnext(q, mp1);
 }
 
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c	Fri Mar 24 12:29:20 2006 -0800
@@ -87,6 +87,8 @@
 	0 },
 { SO_TIMESTAMP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0
 	},
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
 
 { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
 	(OP_PASSNEXT|OP_VARLEN|OP_NODEFAULT),
--- a/usr/src/uts/common/inet/ip/igmp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/igmp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -38,10 +37,8 @@
  * MULTICAST 3.5.1.1
  */
 
-
 #include <sys/types.h>
 #include <sys/stream.h>
-#include <sys/dlpi.h>
 #include <sys/stropts.h>
 #include <sys/strlog.h>
 #include <sys/strsun.h>
@@ -54,12 +51,8 @@
 
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
 #include <inet/ipclassifier.h>
 #include <net/if.h>
-#include <net/if_arp.h>
-#include <sys/sockio.h>
 #include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/igmp_var.h>
@@ -69,7 +62,6 @@
 #include <inet/common.h>
 #include <inet/mi.h>
 #include <inet/nd.h>
-#include <inet/arp.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_multi.h>
@@ -1871,6 +1863,7 @@
 	ill_t 	*ill  = ipif->ipif_ill;	/* Will be the "lower" ill */
 	mblk_t	*first_mp;
 	ipsec_out_t *io;
+	zoneid_t zoneid;
 
 	/*
 	 * We need to make sure this packet goes out on an ipif. If
@@ -1907,7 +1900,9 @@
 	io->ipsec_out_attach_if = B_TRUE;
 	io->ipsec_out_multicast_loop = B_FALSE;
 	io->ipsec_out_dontroute = B_TRUE;
-	io->ipsec_out_zoneid = ilm->ilm_zoneid;
+	if ((zoneid = ilm->ilm_zoneid) == ALL_ZONES)
+		zoneid = GLOBAL_ZONEID;
+	io->ipsec_out_zoneid = zoneid;
 
 	mp = allocb(size, BPRI_HI);
 	if (mp == NULL) {
@@ -1986,6 +1981,7 @@
 	mrec_t *rp, *cur_reclist;
 	mrec_t *next_reclist = reclist;
 	boolean_t morepkts;
+	zoneid_t zoneid;
 
 	/* if there aren't any records, there's nothing to send */
 	if (reclist == NULL)
@@ -2077,7 +2073,9 @@
 	io->ipsec_out_attach_if = B_TRUE;
 	io->ipsec_out_multicast_loop = B_FALSE;
 	io->ipsec_out_dontroute = B_TRUE;
-	io->ipsec_out_zoneid = ipif->ipif_zoneid;
+	if ((zoneid = ipif->ipif_zoneid) == ALL_ZONES)
+		zoneid = GLOBAL_ZONEID;
+	io->ipsec_out_zoneid = zoneid;
 
 	mp = allocb(size, BPRI_HI);
 	if (mp == NULL) {
--- a/usr/src/uts/common/inet/ip/ip.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip.c	Fri Mar 24 12:29:20 2006 -0800
@@ -46,6 +46,7 @@
 #include <sys/modctl.h>
 #include <sys/atomic.h>
 #include <sys/policy.h>
+#include <sys/priv.h>
 
 #include <sys/systm.h>
 #include <sys/param.h>
@@ -113,6 +114,11 @@
 #include <inet/sctp_ip.h>
 #include <inet/udp_impl.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+
+#include <rpc/pmap_prot.h>
+
 /*
  * Values for squeue switch:
  * IP_SQUEUE_ENTER_NODRAIN: squeue_enter_nodrain
@@ -252,6 +258,17 @@
 typedef struct listptr_s listptr_t;
 
 /*
+ * This is used by ip_snmp_get_mib2_ip_route_media and
+ * ip_snmp_get_mib2_ip6_route_media to carry the lists of return data.
+ */
+typedef struct iproutedata_s {
+	uint_t		ird_idx;
+	listptr_t	ird_route;	/* ipRouteEntryTable */
+	listptr_t	ird_netmedia;	/* ipNetToMediaEntryTable */
+	listptr_t	ird_attrs;	/* ipRouteAttributeTable */
+} iproutedata_t;
+
+/*
  * Cluster specific hooks. These should be NULL when booted as a non-cluster
  */
 
@@ -423,18 +440,31 @@
  * ill_g_lock -> ndp_g_lock -> ill_lock -> nce_lock
  * ill_g_lock -> ip_addr_avail_lock
  * conn_lock -> irb_lock -> ill_lock -> ire_lock
- * ipsa_lock -> ill_g_lock -> ill_lock
  * ill_g_lock -> ip_g_nd_lock
- * irb_lock -> ill_lock -> ire_mrtun_lock
- * irb_lock -> ill_lock -> ire_srcif_table_lock
- * ipsec_capab_ills_lock -> ill_g_lock -> ill_lock
- * ipsec_capab_ills_lock -> ipsa_lock
- * ill_g_usesrc_lock -> ill_g_lock -> ill_lock
  *
  * When more than 1 ill lock is needed to be held, all ill lock addresses
  * are sorted on address and locked starting from highest addressed lock
  * downward.
  *
+ * Mobile-IP scenarios
+ *
+ * irb_lock -> ill_lock -> ire_mrtun_lock
+ * irb_lock -> ill_lock -> ire_srcif_table_lock
+ *
+ * IPsec scenarios
+ *
+ * ipsa_lock -> ill_g_lock -> ill_lock
+ * ipsec_capab_ills_lock -> ill_g_lock -> ill_lock
+ * ipsec_capab_ills_lock -> ipsa_lock
+ * ill_g_usesrc_lock -> ill_g_lock -> ill_lock
+ *
+ * Trusted Solaris scenarios
+ *
+ * igsa_lock -> gcgrp_rwlock -> gcgrp_lock
+ * igsa_lock -> gcdb_lock
+ * gcgrp_rwlock -> ire_lock
+ * gcgrp_rwlock -> gcdb_lock
+ *
  * IPSEC notes :
  *
  * IP interacts with the IPSEC code (AH/ESP) by tagging a M_CTL message
@@ -700,9 +730,9 @@
 static mblk_t	*ip_snmp_get_mib2_multi_rtable(queue_t *, mblk_t *);
 static mblk_t	*ip_snmp_get_mib2_ip_route_media(queue_t *, mblk_t *);
 static mblk_t	*ip_snmp_get_mib2_ip6_route_media(queue_t *, mblk_t *);
-static void	ip_snmp_get2_v4(ire_t *, listptr_t []);
-static void	ip_snmp_get2_v6_route(ire_t *, listptr_t *);
-static int	ip_snmp_get2_v6_media(nce_t *, listptr_t *);
+static void	ip_snmp_get2_v4(ire_t *, iproutedata_t *);
+static void	ip_snmp_get2_v6_route(ire_t *, iproutedata_t *);
+static int	ip_snmp_get2_v6_media(nce_t *, iproutedata_t *);
 int		ip_snmp_set(queue_t *, int, int, uchar_t *, int);
 static boolean_t	ip_source_routed(ipha_t *);
 static boolean_t	ip_source_route_included(ipha_t *);
@@ -1666,6 +1696,23 @@
 		if (first_mp == NULL)
 			return;
 	}
+
+	/*
+	 * On a labeled system, we have to check whether the zone itself is
+	 * permitted to receive raw traffic.
+	 */
+	if (is_system_labeled()) {
+		if (zoneid == ALL_ZONES)
+			zoneid = tsol_packet_to_zoneid(mp);
+		if (!tsol_can_accept_raw(mp, B_FALSE)) {
+			ip1dbg(("icmp_inbound: zone %d can't receive raw",
+			    zoneid));
+			BUMP_MIB(&icmp_mib, icmpInErrors);
+			freemsg(first_mp);
+			return;
+		}
+	}
+
 	/*
 	 * We have accepted the ICMP message. It means that we will
 	 * respond to the packet if needed. It may not be delivered
@@ -2037,7 +2084,7 @@
 		 * accept packets for them afterwards.
 		 */
 		src_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_LOCAL,
-		    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+		    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 		if (src_ire == NULL) {
 			ipif = ipif_get_next_ipif(NULL, ill);
 			if (ipif == NULL) {
@@ -2047,7 +2094,7 @@
 			}
 			src_ire = ire_ftable_lookup(ipha->ipha_dst, 0, 0,
 			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
-			    MATCH_IRE_ILL | MATCH_IRE_TYPE);
+			    NULL, MATCH_IRE_ILL | MATCH_IRE_TYPE);
 			ipif_refrele(ipif);
 			if (src_ire != NULL) {
 				onlink = B_TRUE;
@@ -2091,6 +2138,7 @@
 		ii = (ipsec_in_t *)first_mp->b_rptr;
 	}
 	ii->ipsec_in_zoneid = zoneid;
+	ASSERT(zoneid != ALL_ZONES);
 	if (!ipsec_in_to_out(first_mp, ipha, NULL)) {
 		BUMP_MIB(&ip_mib, ipInDiscards);
 		return;
@@ -2124,7 +2172,7 @@
 	hdr_length = IPH_HDR_LENGTH(ipha);
 
 	first_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_CACHE, NULL,
-	    ALL_ZONES, MATCH_IRE_TYPE);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 
 	if (!first_ire) {
 		ip1dbg(("icmp_inbound_too_big: no route for 0x%x\n",
@@ -2144,8 +2192,9 @@
 		mutex_enter(&ire->ire_lock);
 		if (icmph->icmph_du_zero == 0 && mtu > 68) {
 			/* Reduce the IRE max frag value as advised. */
+			ip1dbg(("Received mtu from router: %d (was %d)\n",
+			    mtu, ire->ire_max_frag));
 			ire->ire_max_frag = MIN(ire->ire_max_frag, mtu);
-			ip1dbg(("Received mtu from router: %d\n", mtu));
 		} else {
 			uint32_t length;
 			int	i;
@@ -2761,6 +2810,93 @@
 }
 
 /*
+ * Use the outgoing IP header to create an IP_OPTIONS option the way
+ * it was passed down from the application.
+ */
+int
+ip_opt_get_user(const ipha_t *ipha, uchar_t *buf)
+{
+	ipoptp_t	opts;
+	const uchar_t	*opt;
+	uint8_t		optval;
+	uint8_t		optlen;
+	uint32_t	len = 0;
+	uchar_t	*buf1 = buf;
+
+	buf += IP_ADDR_LEN;	/* Leave room for final destination */
+	len += IP_ADDR_LEN;
+	bzero(buf1, IP_ADDR_LEN);
+
+	/*
+	 * OK to cast away const here, as we don't store through the returned
+	 * opts.ipoptp_cur pointer.
+	 */
+	for (optval = ipoptp_first(&opts, (ipha_t *)ipha);
+	    optval != IPOPT_EOL;
+	    optval = ipoptp_next(&opts)) {
+		int	off;
+
+		opt = opts.ipoptp_cur;
+		optlen = opts.ipoptp_len;
+		switch (optval) {
+		case IPOPT_SSRR:
+		case IPOPT_LSRR:
+
+			/*
+			 * Insert ipha_dst as the first entry in the source
+			 * route and move down the entries on step.
+			 * The last entry gets placed at buf1.
+			 */
+			buf[IPOPT_OPTVAL] = optval;
+			buf[IPOPT_OLEN] = optlen;
+			buf[IPOPT_OFFSET] = optlen;
+
+			off = optlen - IP_ADDR_LEN;
+			if (off < 0) {
+				/* No entries in source route */
+				break;
+			}
+			/* Last entry in source route */
+			bcopy(opt + off, buf1, IP_ADDR_LEN);
+			off -= IP_ADDR_LEN;
+
+			while (off > 0) {
+				bcopy(opt + off,
+				    buf + off + IP_ADDR_LEN,
+				    IP_ADDR_LEN);
+				off -= IP_ADDR_LEN;
+			}
+			/* ipha_dst into first slot */
+			bcopy(&ipha->ipha_dst,
+			    buf + off + IP_ADDR_LEN,
+			    IP_ADDR_LEN);
+			buf += optlen;
+			len += optlen;
+			break;
+
+		case IPOPT_COMSEC:
+		case IPOPT_SECURITY:
+			/* if passing up a label is not ok, then remove */
+			if (is_system_labeled())
+				break;
+			/* FALLTHROUGH */
+		default:
+			bcopy(opt, buf, optlen);
+			buf += optlen;
+			len += optlen;
+			break;
+		}
+	}
+done:
+	/* Pad the resulting options */
+	while (len & 0x3) {
+		*buf++ = IPOPT_EOL;
+		len++;
+	}
+	return (len);
+}
+
+/*
  * Update any record route or timestamp options to include this host.
  * Reverse any source route option.
  * This routine assumes that the options are well formed i.e. that they
@@ -2856,14 +2992,14 @@
 	gateway = icmph->icmph_rd_gateway;
 	/* Make sure the new gateway is reachable somehow. */
 	ire = ire_route_lookup(gateway, 0, 0, IRE_INTERFACE, NULL, NULL,
-	    ALL_ZONES, MATCH_IRE_TYPE);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	/*
 	 * Make sure we had a route for the dest in question and that
 	 * that route was pointing to the old gateway (the source of the
 	 * redirect packet.)
 	 */
 	prev_ire = ire_route_lookup(dst, 0, src, 0, NULL, NULL, ALL_ZONES,
-	    MATCH_IRE_GW);
+	    NULL, MATCH_IRE_GW);
 	/*
 	 * Check that
 	 *	the redirect was not from ourselves
@@ -2903,7 +3039,7 @@
 		ire_t *sire;
 
 		tmp_ire = ire_ftable_lookup(dst, 0, gateway, 0, NULL, &sire,
-		    ALL_ZONES, 0,
+		    ALL_ZONES, 0, NULL,
 		    (MATCH_IRE_RECURSIVE | MATCH_IRE_GW | MATCH_IRE_DEFAULT));
 		if (sire != NULL) {
 			bcopy(&sire->ire_uinfo, &ulp_info, sizeof (iulp_t));
@@ -2963,7 +3099,9 @@
 		0,
 		0,
 		(RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST),
-		&ulp_info);
+		&ulp_info,
+		NULL,
+		NULL);
 
 	if (ire == NULL) {
 		freemsg(mp);
@@ -2986,7 +3124,7 @@
 	 * modifying an existing redirect.
 	 */
 	prev_ire = ire_ftable_lookup(dst, 0, src, IRE_HOST_REDIRECT, NULL, NULL,
-	    ALL_ZONES, 0, (MATCH_IRE_GW | MATCH_IRE_TYPE));
+	    ALL_ZONES, 0, NULL, (MATCH_IRE_GW | MATCH_IRE_TYPE));
 	if (prev_ire) {
 		ire_delete(prev_ire);
 		ire_refrele(prev_ire);
@@ -3120,6 +3258,7 @@
 			zoneid = GLOBAL_ZONEID;
 		}
 		ii->ipsec_in_zoneid = zoneid;
+		ASSERT(zoneid != ALL_ZONES);
 		ipsec_mp->b_cont = mp;
 		ipha = (ipha_t *)mp->b_rptr;
 		/*
@@ -3136,13 +3275,14 @@
 	dst = ipha->ipha_src;
 
 	ire = ire_route_lookup(ipha->ipha_dst, 0, 0, (IRE_LOCAL|IRE_LOOPBACK),
-	    NULL, NULL, zoneid, MATCH_IRE_TYPE);
-	if (ire != NULL && ire->ire_zoneid == zoneid) {
+	    NULL, NULL, zoneid, NULL, MATCH_IRE_TYPE);
+	if (ire != NULL &&
+	    (ire->ire_zoneid == zoneid || ire->ire_zoneid == ALL_ZONES)) {
 		src = ipha->ipha_dst;
 	} else if (!xmit_if_on) {
 		if (ire != NULL)
 			ire_refrele(ire);
-		ire = ire_route_lookup(dst, 0, 0, 0, NULL, NULL, zoneid,
+		ire = ire_route_lookup(dst, 0, 0, 0, NULL, NULL, zoneid, NULL,
 		    (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE|MATCH_IRE_ZONEONLY));
 		if (ire == NULL) {
 			BUMP_MIB(&ip_mib, ipOutNoRoutes);
@@ -3187,18 +3327,29 @@
 	 * Check if we can send back more then 8 bytes in addition
 	 * to the IP header. We will include as much as 64 bytes.
 	 */
-	len_needed = IPH_HDR_LENGTH(ipha) + ip_icmp_return;
+	len_needed = IPH_HDR_LENGTH(ipha);
+	if (ipha->ipha_protocol == IPPROTO_ENCAP &&
+	    (uchar_t *)ipha + len_needed + 1 <= mp->b_wptr) {
+		len_needed += IPH_HDR_LENGTH(((uchar_t *)ipha + len_needed));
+	}
+	len_needed += ip_icmp_return;
 	msg_len = msgdsize(mp);
 	if (msg_len > len_needed) {
 		(void) adjmsg(mp, len_needed - msg_len);
 		msg_len = len_needed;
 	}
 	mp1 = allocb(sizeof (icmp_ipha) + len, BPRI_HI);
-	if (!mp1) {
+	if (mp1 == NULL) {
 		BUMP_MIB(&icmp_mib, icmpOutErrors);
 		freemsg(ipsec_mp);
 		return;
 	}
+	/*
+	 * On an unlabeled system, dblks don't necessarily have creds.
+	 */
+	ASSERT(!is_system_labeled() || DB_CRED(mp) != NULL);
+	if (DB_CRED(mp) != NULL)
+		mblk_setcred(mp1, DB_CRED(mp));
 	mp1->b_cont = mp;
 	mp = mp1;
 	ASSERT(ipsec_mp->b_datap->db_type == M_CTL &&
@@ -3314,9 +3465,9 @@
 		return (NULL);
 	}
 	src_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_BROADCAST,
-	    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	dst_ire = ire_ctable_lookup(ipha->ipha_src, 0, IRE_BROADCAST,
-	    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	if (src_ire != NULL || dst_ire != NULL ||
 	    CLASSD(ipha->ipha_dst) ||
 	    CLASSD(ipha->ipha_src) ||
@@ -3359,6 +3510,16 @@
 			break;
 		}
 	}
+	/*
+	 * If this is a labeled system, then check to see if we're allowed to
+	 * send a response to this particular sender.  If not, then just drop.
+	 */
+	if (is_system_labeled() && !tsol_can_reply_error(mp)) {
+		ip2dbg(("icmp_pkt_err_ok: can't respond to packet\n"));
+		BUMP_MIB(&icmp_mib, icmpOutDrops);
+		freemsg(mp);
+		return (NULL);
+	}
 	if (icmp_err_rate_limit()) {
 		/*
 		 * Only send ICMP error packets every so often.
@@ -3515,9 +3676,9 @@
 			cp1[-1] = '\0';
 		(void) ip_dot_addr(src, sbuf);
 		if (isv6)
-			ire = ire_cache_lookup_v6(&v6src, ALL_ZONES);
+			ire = ire_cache_lookup_v6(&v6src, ALL_ZONES, NULL);
 		else
-			ire = ire_cache_lookup(src, ALL_ZONES);
+			ire = ire_cache_lookup(src, ALL_ZONES, NULL);
 
 		if (ire != NULL	&& IRE_IS_LOCAL(ire)) {
 			cmn_err(CE_WARN,
@@ -3579,7 +3740,7 @@
 		 */
 		if ((ip_ire_clookup_and_delete(src, NULL) ||
 		    (ire = ire_ftable_lookup(src, 0, 0, 0, NULL, NULL, NULL,
-		    0, MATCH_IRE_DSTONLY)) != NULL) && src != 0) {
+		    0, NULL, MATCH_IRE_DSTONLY)) != NULL) && src != 0) {
 			ire_walk_v4(ire_delete_cache_gw, (char *)&src,
 			    ALL_ZONES);
 		}
@@ -3766,6 +3927,18 @@
 			goto bad_addr;
 		}
 
+		/*
+		 *
+		 * The udp module never sends down a zero-length address,
+		 * and allowing this on a labeled system will break MLP
+		 * functionality.
+		 */
+		if (is_system_labeled() && protocol == IPPROTO_UDP)
+			goto bad_addr;
+
+		if (connp->conn_mac_exempt)
+			goto bad_addr;
+
 		/* No hash here really.  The table is big enough. */
 		connp->conn_srcv6 = ipv6_all_zeros;
 
@@ -3904,6 +4077,8 @@
  * In all the above cases, the bound address must be valid in the current zone.
  * When the address is loopback, multicast or broadcast, there might be many
  * matching IREs so bind has to look up based on the zone.
+ *
+ * Note: lport is in network byte order.
  */
 int
 ip_bind_laddr(conn_t *connp, mblk_t *mp, ipaddr_t src_addr, uint16_t lport,
@@ -3933,7 +4108,7 @@
 
 	if (src_addr) {
 		src_ire = ire_route_lookup(src_addr, 0, 0, 0,
-		    NULL, NULL, zoneid, MATCH_IRE_ZONEONLY);
+		    NULL, NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
 		/*
 		 * If an address other than 0.0.0.0 is requested,
 		 * we verify that it is a valid address for bind
@@ -3984,7 +4159,7 @@
 				 */
 				src_ire = ire_ctable_lookup(
 				    INADDR_BROADCAST, INADDR_ANY,
-				    IRE_BROADCAST, NULL, zoneid,
+				    IRE_BROADCAST, NULL, zoneid, NULL,
 				    (MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY));
 				if (src_ire == NULL || !ire_requested)
 					error = EADDRNOTAVAIL;
@@ -4033,7 +4208,7 @@
 		 */
 		error = ipcl_bind_insert(connp, *mp->b_wptr, src_addr, lport);
 	}
-done:
+
 	if (error == 0) {
 		if (ire_requested) {
 			if (!ip_bind_insert_ire(mp, src_ire, NULL)) {
@@ -4048,6 +4223,14 @@
 		}
 	}
 bad_addr:
+	if (error != 0) {
+		if (connp->conn_anon_port) {
+			(void) tsol_mlp_anon(crgetzone(connp->conn_cred),
+			    connp->conn_mlp_type, connp->conn_ulp, ntohs(lport),
+			    B_FALSE);
+		}
+		connp->conn_mlp_type = mlptSingle;
+	}
 	if (src_ire != NULL)
 		IRE_REFRELE(src_ire);
 	if (ipsec_policy_set) {
@@ -4075,6 +4258,8 @@
  * Returns zero if ok.
  * On error: returns -1 to mean TBADADDR otherwise returns an errno
  * (for use with TSYSERR reply).
+ *
+ * Note: lport and fport are in network byte order.
  */
 int
 ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp,
@@ -4110,8 +4295,10 @@
 	if (CLASSD(dst_addr)) {
 		/* Pick up an IRE_BROADCAST */
 		dst_ire = ire_route_lookup(ip_g_all_ones, 0, 0, 0, NULL,
-		    NULL, zoneid, (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-		    MATCH_IRE_RJ_BHOLE));
+		    NULL, zoneid, MBLK_GETLABEL(mp),
+		    (MATCH_IRE_RECURSIVE |
+		    MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE |
+		    MATCH_IRE_SECATTR));
 	} else {
 		/*
 		 * If conn_dontroute is set or if conn_nexthop_set is set,
@@ -4131,12 +4318,14 @@
 
 		if (connp->conn_nexthop_set) {
 			dst_ire = ire_route_lookup(connp->conn_nexthop_v4, 0,
-			    0, 0, NULL, NULL, zoneid, 0);
+			    0, 0, NULL, NULL, zoneid, MBLK_GETLABEL(mp),
+			    MATCH_IRE_SECATTR);
 		} else {
 			dst_ire = ire_route_lookup(dst_addr, 0, 0, 0, NULL,
-			    &sire, zoneid,
+			    &sire, zoneid, MBLK_GETLABEL(mp),
 			    (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-			    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE));
+			    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE |
+			    MATCH_IRE_SECATTR));
 		}
 	}
 	/*
@@ -4175,6 +4364,34 @@
 			goto bad_addr;
 		}
 	}
+
+	/*
+	 * We now know that routing will allow us to reach the destination.
+	 * Check whether Trusted Solaris policy allows communication with this
+	 * host, and pretend that the destination is unreachable if not.
+	 *
+	 * This is never a problem for TCP, since that transport is known to
+	 * compute the label properly as part of the tcp_rput_other T_BIND_ACK
+	 * handling.  If the remote is unreachable, it will be detected at that
+	 * point, so there's no reason to check it here.
+	 *
+	 * Note that for sendto (and other datagram-oriented friends), this
+	 * check is done as part of the data path label computation instead.
+	 * The check here is just to make non-TCP connect() report the right
+	 * error.
+	 */
+	if (dst_ire != NULL && is_system_labeled() &&
+	    !IPCL_IS_TCP(connp) &&
+	    tsol_compute_label(DB_CREDDEF(mp, connp->conn_cred), dst_addr, NULL,
+	    connp->conn_mac_exempt) != 0) {
+		error = EHOSTUNREACH;
+		if (ip_debug > 2) {
+			pr_addr_dbg("ip_bind_connected: no label for dst %s\n",
+			    AF_INET, &dst_addr);
+		}
+		goto bad_addr;
+	}
+
 	/*
 	 * If the app does a connect(), it means that it will most likely
 	 * send more than 1 packet to the destination.  It makes sense
@@ -4212,14 +4429,14 @@
 
 	if (dst_ire != NULL &&
 	    dst_ire->ire_type == IRE_LOCAL &&
-	    dst_ire->ire_zoneid != zoneid) {
+	    dst_ire->ire_zoneid != zoneid && dst_ire->ire_zoneid != ALL_ZONES) {
 		/*
 		 * If the IRE belongs to a different zone, look for a matching
 		 * route in the forwarding table and use the source address from
 		 * that route.
 		 */
 		src_ire = ire_ftable_lookup(dst_addr, 0, 0, 0, NULL, NULL,
-		    zoneid, 0,
+		    zoneid, 0, NULL,
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
 		    MATCH_IRE_RJ_BHOLE);
 		if (src_ire == NULL) {
@@ -4271,11 +4488,12 @@
 			 *    group, then try selecting a source address from
 			 *    the usesrc ILL.
 			 */
-			if (!(dst_ire->ire_type & IRE_BROADCAST) &&
+			if ((dst_ire->ire_zoneid != zoneid &&
+			    dst_ire->ire_zoneid != ALL_ZONES) ||
+			    (!(dst_ire->ire_type & IRE_BROADCAST) &&
 			    ((dst_ill->ill_group != NULL) ||
-			    (dst_ire->ire_ipif->ipif_flags &
-			    IPIF_DEPRECATED) ||
-			    (dst_ill->ill_usesrc_ifindex != 0))) {
+			    (dst_ire->ire_ipif->ipif_flags & IPIF_DEPRECATED) ||
+			    (dst_ill->ill_usesrc_ifindex != 0)))) {
 				/*
 				 * If the destination is reachable via a
 				 * given gateway, the selected source address
@@ -4335,7 +4553,7 @@
 	 */
 	ASSERT(src_ire == NULL);
 	src_ire = ire_route_lookup(src_addr, 0, 0, 0, NULL,
-	    NULL, zoneid, MATCH_IRE_ZONEONLY);
+	    NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
 	/* src_ire must be a local|loopback */
 	if (!IRE_IS_LOCAL(src_ire)) {
 		if (ip_debug > 2) {
@@ -4785,6 +5003,14 @@
 	if (conn_ioctl_cleanup_reqd)
 		conn_ioctl_cleanup(connp);
 
+	if (is_system_labeled() && connp->conn_anon_port) {
+		(void) tsol_mlp_anon(crgetzone(connp->conn_cred),
+		    connp->conn_mlp_type, connp->conn_ulp,
+		    ntohs(connp->conn_lport), B_FALSE);
+		connp->conn_anon_port = 0;
+	}
+	connp->conn_mlp_type = mlptSingle;
+
 	/*
 	 * Remove this conn from any fanout list it is on.
 	 * and then wait for any threads currently operating
@@ -4877,10 +5103,6 @@
 		freemsg(connp->conn_ipsec_opt_mp);
 		connp->conn_ipsec_opt_mp = NULL;
 	}
-	if (connp->conn_cred != NULL) {
-		crfree(connp->conn_cred);
-		connp->conn_cred = NULL;
-	}
 
 	inet_minor_free(ip_minor_arena, connp->conn_dev);
 
@@ -4998,6 +5220,7 @@
 void
 ip_ddi_destroy(void)
 {
+	tnet_fini();
 	tcp_ddi_destroy();
 	sctp_ddi_destroy();
 	ipsec_loader_destroy();
@@ -5088,8 +5311,8 @@
 	ip_kstat_init();
 	ip6_kstat_init();
 	icmp_kstat_init();
-
 	ipsec_loader_start();
+	tnet_init();
 }
 
 /*
@@ -5299,30 +5522,6 @@
 	return (B_TRUE);
 }
 
-#ifdef DEBUG
-/*
- * Copy the header into the IPSEC_IN message.
- */
-static void
-ipsec_inbound_debug_tag(mblk_t *ipsec_mp)
-{
-	mblk_t *data_mp = ipsec_mp->b_cont;
-	ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
-	ipha_t *ipha;
-
-	if (ii->ipsec_in_type != IPSEC_IN)
-		return;
-	ASSERT(data_mp != NULL);
-
-	ipha = (ipha_t *)data_mp->b_rptr;
-	bcopy(ipha, ii->ipsec_in_saved_hdr,
-	    (IPH_HDR_VERSION(ipha) == IP_VERSION) ?
-	    sizeof (ipha_t) : sizeof (ip6_t));
-}
-#else
-#define	ipsec_inbound_debug_tag(x)	/* NOP */
-#endif	/* DEBUG */
-
 /*
  * Used to send an ICMP error message when a packet is received for
  * a protocol that is not supported. The mblk passed as argument
@@ -5442,6 +5641,7 @@
 	uint32_t ill_index;
 	conn_t	*connp, *first_connp, *next_connp;
 	connf_t	*connfp;
+	boolean_t shared_addr;
 
 	if (mctl_present) {
 		mp = first_mp->b_cont;
@@ -5458,12 +5658,25 @@
 	one_only = ((protocol == IPPROTO_ENCAP || protocol == IPPROTO_IPV6) &&
 	    !CLASSD(dst));
 
+	shared_addr = (zoneid == ALL_ZONES);
+	if (shared_addr) {
+		/*
+		 * We don't allow multilevel ports for raw IP, so no need to
+		 * check for that here.
+		 */
+		zoneid = tsol_packet_to_zoneid(mp);
+	}
+
 	connfp = &ipcl_proto_fanout[protocol];
 	mutex_enter(&connfp->connf_lock);
 	connp = connfp->connf_head;
 	for (connp = connfp->connf_head; connp != NULL;
 		connp = connp->conn_next) {
-		if (IPCL_PROTO_MATCH(connp, protocol, ipha, ill, flags, zoneid))
+		if (IPCL_PROTO_MATCH(connp, protocol, ipha, ill, flags,
+		    zoneid) &&
+		    (!is_system_labeled() ||
+		    tsol_receive_local(mp, &dst, IPV4_VERSION, shared_addr,
+		    connp)))
 			break;
 	}
 
@@ -5518,7 +5731,10 @@
 	for (;;) {
 		while (connp != NULL) {
 			if (IPCL_PROTO_MATCH(connp, protocol, ipha, ill,
-			    flags, zoneid))
+			    flags, zoneid) &&
+			    (!is_system_labeled() ||
+			    tsol_receive_local(mp, &dst, IPV4_VERSION,
+			    shared_addr, connp)))
 				break;
 			connp = connp->conn_next;
 		}
@@ -5704,6 +5920,8 @@
 				return;
 		}
 		BUMP_MIB(&ip_mib, ipInDelivers);
+		ip2dbg(("ip_fanout_tcp: no listener; send reset to zone %d\n",
+		    zoneid));
 		tcp_xmit_listeners_reset(first_mp, ip_hdr_len);
 		return;
 	}
@@ -5956,6 +6174,7 @@
 	ipaddr_t	src;
 	zoneid_t	last_zoneid;
 	boolean_t	reuseaddr;
+	boolean_t	shared_addr;
 
 	first_mp = mp;
 	if (mctl_present) {
@@ -5974,6 +6193,13 @@
 	dst = ipha->ipha_dst;
 	src = ipha->ipha_src;
 
+	shared_addr = (zoneid == ALL_ZONES);
+	if (shared_addr) {
+		zoneid = tsol_mlp_findzone(IPPROTO_UDP, dstport);
+		if (zoneid == ALL_ZONES)
+			zoneid = tsol_packet_to_zoneid(mp);
+	}
+
 	connfp = &ipcl_udp_fanout[IPCL_UDP_HASH(dstport)];
 	mutex_enter(&connfp->connf_lock);
 	connp = connfp->connf_head;
@@ -5992,6 +6218,12 @@
 
 		if (connp == NULL || connp->conn_upq == NULL)
 			goto notfound;
+
+		if (is_system_labeled() &&
+		    !tsol_receive_local(mp, &dst, IPV4_VERSION, shared_addr,
+		    connp))
+			goto notfound;
+
 		CONN_INC_REF(connp);
 		mutex_exit(&connfp->connf_lock);
 		ip_fanout_udp_conn(connp, first_mp, mp, secure, ipha, flags,
@@ -6012,7 +6244,10 @@
 
 	while (connp != NULL) {
 		if ((IPCL_UDP_MATCH(connp, dstport, dst, srcport, src)) &&
-		    conn_wantpacket(connp, ill, ipha, flags, zoneid))
+		    conn_wantpacket(connp, ill, ipha, flags, zoneid) &&
+		    (!is_system_labeled() ||
+		    tsol_receive_local(mp, &dst, IPV4_VERSION, shared_addr,
+		    connp)))
 			break;
 		connp = connp->conn_next;
 	}
@@ -6034,7 +6269,10 @@
 		while (connp != NULL) {
 			if (IPCL_UDP_MATCH(connp, dstport, dst, srcport, src) &&
 			    (reuseaddr || connp->conn_zoneid != last_zoneid) &&
-			    conn_wantpacket(connp, ill, ipha, flags, zoneid))
+			    conn_wantpacket(connp, ill, ipha, flags, zoneid) &&
+			    (!is_system_labeled() ||
+			    tsol_receive_local(mp, &dst, IPV4_VERSION,
+			    shared_addr, connp)))
 				break;
 			connp = connp->conn_next;
 		}
@@ -6127,6 +6365,11 @@
 			connp = connp->conn_next;
 		}
 
+		if (connp != NULL && is_system_labeled() &&
+		    !tsol_receive_local(mp, &dst, IPV4_VERSION, shared_addr,
+		    connp))
+			connp = NULL;
+
 		if (connp == NULL || connp->conn_upq == NULL) {
 			/*
 			 * No one bound to this port.  Is
@@ -6153,6 +6396,7 @@
 			}
 			return;
 		}
+
 		CONN_INC_REF(connp);
 		mutex_exit(&connfp->connf_lock);
 		ip_fanout_udp_conn(connp, first_mp, mp, secure, ipha, flags,
@@ -6172,7 +6416,10 @@
 	while (connp != NULL) {
 		if (IPCL_UDP_MATCH_V6(connp, dstport, ipv6_all_zeros,
 		    srcport, v6src) &&
-		    conn_wantpacket(connp, ill, ipha, flags, zoneid))
+		    conn_wantpacket(connp, ill, ipha, flags, zoneid) &&
+		    (!is_system_labeled() ||
+		    tsol_receive_local(mp, &dst, IPV4_VERSION, shared_addr,
+		    connp)))
 			break;
 		connp = connp->conn_next;
 	}
@@ -6214,7 +6461,10 @@
 		while (connp != NULL) {
 			if (IPCL_UDP_MATCH_V6(connp, dstport,
 			    ipv6_all_zeros, srcport, v6src) &&
-			    conn_wantpacket(connp, ill, ipha, flags, zoneid))
+			    conn_wantpacket(connp, ill, ipha, flags, zoneid) &&
+			    (!is_system_labeled() ||
+			    tsol_receive_local(mp, &dst, IPV4_VERSION,
+			    shared_addr, connp)))
 				break;
 			connp = connp->conn_next;
 		}
@@ -6378,7 +6628,7 @@
 			 * for source route?
 			 */
 			ire = ire_ctable_lookup(dst, 0, IRE_LOCAL, NULL,
-			    ALL_ZONES, MATCH_IRE_TYPE);
+			    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (ire != NULL) {
 				ire_refrele(ire);
 				off += IP_ADDR_LEN;
@@ -6746,6 +6996,9 @@
 	boolean_t do_attach_ill = B_FALSE;
 	boolean_t ip_nexthop = B_FALSE;
 	zoneid_t zoneid;
+	tsol_ire_gw_secattr_t *attrp = NULL;
+	tsol_gcgrp_t *gcgrp = NULL;
+	tsol_gcgrp_addr_t ga;
 
 	if (ip_debug > 2) {
 		/* ip1dbg */
@@ -6835,23 +7088,26 @@
 		 * nexthop address and create an IRE_CACHE entry for the
 		 * destination address via the specified nexthop.
 		 */
-		ire = ire_cache_lookup(nexthop_addr, zoneid);
+		ire = ire_cache_lookup(nexthop_addr, zoneid,
+		    MBLK_GETLABEL(mp));
 		if (ire != NULL) {
 			gw = nexthop_addr;
 			ire_marks |= IRE_MARK_PRIVATE_ADDR;
 		} else {
 			ire = ire_ftable_lookup(nexthop_addr, 0, 0,
 			    IRE_INTERFACE, NULL, NULL, zoneid, 0,
-			    MATCH_IRE_TYPE);
+			    MBLK_GETLABEL(mp),
+			    MATCH_IRE_TYPE | MATCH_IRE_SECATTR);
 			if (ire != NULL) {
 				dst = nexthop_addr;
 			}
 		}
 	} else if (attach_ill == NULL) {
 		ire = ire_ftable_lookup(dst, 0, 0, 0,
-		    NULL, &sire, zoneid, 0,
+		    NULL, &sire, zoneid, 0, MBLK_GETLABEL(mp),
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-		    MATCH_IRE_RJ_BHOLE | MATCH_IRE_PARENT);
+		    MATCH_IRE_RJ_BHOLE | MATCH_IRE_PARENT |
+		    MATCH_IRE_SECATTR);
 	} else {
 		/*
 		 * attach_ill is set only for communicating with
@@ -6865,8 +7121,9 @@
 			goto icmp_err_ret;
 		}
 		ire = ire_ftable_lookup(dst, 0, 0, 0, attach_ipif,
-		    &sire, zoneid, 0,
-		    MATCH_IRE_RJ_BHOLE | MATCH_IRE_ILL);
+		    &sire, zoneid, 0, MBLK_GETLABEL(mp),
+		    MATCH_IRE_RJ_BHOLE | MATCH_IRE_ILL |
+		    MATCH_IRE_SECATTR);
 		ipif_refrele(attach_ipif);
 	}
 	ip3dbg(("ip_newroute: ire_ftable_lookup() "
@@ -6906,7 +7163,8 @@
 
 			ASSERT(sire != NULL);
 			multirt_is_resolvable =
-			    ire_multirt_lookup(&ire, &sire, multirt_flags);
+			    ire_multirt_lookup(&ire, &sire, multirt_flags,
+				MBLK_GETLABEL(mp));
 
 			ip3dbg(("ip_newroute: multirt_is_resolvable %d, "
 			    "ire %p, sire %p\n",
@@ -7152,7 +7410,8 @@
 			ire_marks |= IRE_MARK_USESRC_CHECK;
 			if ((dst_ill->ill_group != NULL) ||
 			    (ire->ire_ipif->ipif_flags & IPIF_DEPRECATED) ||
-			    (connp != NULL && ire->ire_zoneid != zoneid) ||
+			    (connp != NULL && ire->ire_zoneid != zoneid &&
+			    ire->ire_zoneid != ALL_ZONES) ||
 			    (dst_ill->ill_usesrc_ifindex != 0)) {
 				/*
 				 * If the destination is reachable via a
@@ -7338,6 +7597,18 @@
 			if (save_ire->ire_stq == dst_ill->ill_wq)
 				ire_fp_mp = save_ire->ire_fp_mp;
 
+			/*
+			 * Check cached gateway IRE for any security
+			 * attributes; if found, associate the gateway
+			 * credentials group to the destination IRE.
+			 */
+			if ((attrp = save_ire->ire_gw_secattr) != NULL) {
+				mutex_enter(&attrp->igsa_lock);
+				if ((gcgrp = attrp->igsa_gcgrp) != NULL)
+					GCGRP_REFHOLD(gcgrp);
+				mutex_exit(&attrp->igsa_lock);
+			}
+
 			ire = ire_create(
 			    (uchar_t *)&dst,		/* dest address */
 			    (uchar_t *)&ip_g_all_ones,	/* mask */
@@ -7360,13 +7631,23 @@
 			    (sire != NULL) ? (sire->ire_flags &
 				(RTF_SETSRC | RTF_MULTIRT)) : 0, /* flags */
 			    (sire != NULL) ?
-				&(sire->ire_uinfo) : &(save_ire->ire_uinfo));
+				&(sire->ire_uinfo) : &(save_ire->ire_uinfo),
+			    NULL,
+			    gcgrp);
 
 			if (ire == NULL) {
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
 				ire_refrele(ipif_ire);
 				ire_refrele(save_ire);
 				break;
 			}
+
+			/* reference now held by IRE */
+			gcgrp = NULL;
+
 			ire->ire_marks |= ire_marks;
 
 			/*
@@ -7475,6 +7756,23 @@
 				break;
 			}
 
+			/*
+			 * TSol note: We are creating the ire cache for the
+			 * destination 'dst'. If 'dst' is offlink, going
+			 * through the first hop 'gw', the security attributes
+			 * of 'dst' must be set to point to the gateway
+			 * credentials of gateway 'gw'. If 'dst' is onlink, it
+			 * is possible that 'dst' is a potential gateway that is
+			 * referenced by some route that has some security
+			 * attributes. Thus in the former case, we need to do a
+			 * gcgrp_lookup of 'gw' while in the latter case we
+			 * need to do gcgrp_lookup of 'dst' itself.
+			 */
+			ga.ga_af = AF_INET;
+			IN6_IPADDR_TO_V4MAPPED(gw != INADDR_ANY ? gw : dst,
+			    &ga.ga_addr);
+			gcgrp = gcgrp_lookup(&ga, B_FALSE);
+
 			ire = ire_create(
 			    (uchar_t *)&dst,		/* dest address */
 			    (uchar_t *)&ip_g_all_ones,	/* mask */
@@ -7495,16 +7793,25 @@
 			    save_ire->ire_ihandle,	/* Interface handle */
 			    (sire != NULL) ? sire->ire_flags &
 				(RTF_SETSRC | RTF_MULTIRT) : 0, /* flags */
-			    &(save_ire->ire_uinfo));
+			    &(save_ire->ire_uinfo),
+			    NULL,
+			    gcgrp);
 
 			if (dst_ill->ill_phys_addr_length == IP_ADDR_LEN)
 				freeb(dlureq_mp);
 
 			if (ire == NULL) {
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
 				ire_refrele(save_ire);
 				break;
 			}
 
+			/* reference now held by IRE */
+			gcgrp = NULL;
+
 			ire->ire_marks |= ire_marks;
 
 			/* Prevent save_ire from getting deleted */
@@ -7587,6 +7894,7 @@
 			res_mp = dst_ill->ill_resolver_mp;
 			if (!OK_RESOLVER_MP(res_mp))
 				break;
+
 			/*
 			 * To be at this point in the code with a non-zero gw
 			 * means that dst is reachable through a gateway that
@@ -7626,6 +7934,15 @@
 				dst = gw;
 				gw = INADDR_ANY;
 			}
+
+			/*
+			 * TSol note: Please see the corresponding note
+			 * of the IRE_IF_NORESOLVER case
+			 */
+			ga.ga_af = AF_INET;
+			IN6_IPADDR_TO_V4MAPPED(dst, &ga.ga_addr);
+			gcgrp = gcgrp_lookup(&ga, B_FALSE);
+
 			/*
 			 * We obtain a partial IRE_CACHE which we will pass
 			 * along with the resolver query.  When the response
@@ -7651,12 +7968,21 @@
 			    0,
 			    save_ire->ire_ihandle,	/* Interface handle */
 			    0,				/* flags if any */
-			    &(save_ire->ire_uinfo));
+			    &(save_ire->ire_uinfo),
+			    NULL,
+			    gcgrp);
 
 			if (ire == NULL) {
 				ire_refrele(save_ire);
-				break;
-			}
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
+				break;
+			}
+
+			/* reference now held by IRE */
+			gcgrp = NULL;
 
 			if ((sire != NULL) &&
 			    (sire->ire_flags & RTF_MULTIRT)) {
@@ -8065,7 +8391,8 @@
 			    zoneid, NULL, NULL, NULL, NULL);
 		}
 		if (((ipif->ipif_flags & IPIF_DEPRECATED) ||
-		    (connp != NULL && ipif->ipif_zoneid != zoneid)) &&
+		    (connp != NULL && ipif->ipif_zoneid != zoneid &&
+		    ipif->ipif_zoneid != ALL_ZONES)) &&
 		    (src_ipif == NULL)) {
 			src_ipif = ipif_select_source(dst_ill, dst, zoneid);
 			if (src_ipif == NULL) {
@@ -8221,7 +8548,9 @@
 				(fire->ire_flags &
 				(RTF_SETSRC | RTF_MULTIRT)) : 0,
 			    (save_ire == NULL ? &ire_uinfo_null :
-				&save_ire->ire_uinfo));
+				&save_ire->ire_uinfo),
+			    NULL,
+			    NULL);
 
 			freeb(dlureq_mp);
 
@@ -8278,7 +8607,8 @@
 			 */
 			if ((flags & RTF_MULTIRT) && (copy_mp != NULL)) {
 				boolean_t need_resolve =
-				    ire_multirt_need_resolve(ipha_dst);
+				    ire_multirt_need_resolve(ipha_dst,
+					MBLK_GETLABEL(copy_mp));
 				if (!need_resolve) {
 					MULTIRT_DEBUG_UNTAG(copy_mp);
 					freemsg(copy_mp);
@@ -8361,7 +8691,9 @@
 				(fire->ire_flags &
 				(RTF_SETSRC | RTF_MULTIRT)) : 0,
 			    (save_ire == NULL ? &ire_uinfo_null :
-				&save_ire->ire_uinfo));
+				&save_ire->ire_uinfo),
+			    NULL,
+			    NULL);
 
 			if (save_ire != NULL) {
 				ire_refrele(save_ire);
@@ -8442,7 +8774,8 @@
 			 */
 			if ((flags & RTF_MULTIRT) && (copy_mp != NULL)) {
 				boolean_t need_resolve =
-				    ire_multirt_need_resolve(ipha_dst);
+				    ire_multirt_need_resolve(ipha_dst,
+					MBLK_GETLABEL(copy_mp));
 				if (!need_resolve) {
 					MULTIRT_DEBUG_UNTAG(copy_mp);
 					freemsg(copy_mp);
@@ -8703,11 +9036,18 @@
 	*devp = makedevice(maj, (minor_t)connp->conn_dev);
 
 	/*
-	 * connp->conn_cred is crfree()ed in ip_close().
+	 * connp->conn_cred is crfree()ed in ipcl_conn_destroy()
 	 */
 	connp->conn_cred = credp;
 	crhold(connp->conn_cred);
 
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		connp->conn_mac_exempt = B_TRUE;
+
 	connp->conn_zoneid = getzoneid();
 
 	/*
@@ -9576,6 +9916,23 @@
 				mutex_exit(&connp->conn_lock);
 			}
 			break;	/* goto sizeof (int) option return */
+		case SO_ANON_MLP:
+			if (!checkonly) {
+				mutex_enter(&connp->conn_lock);
+				connp->conn_anon_mlp = *i1 != 0 ? 1 : 0;
+				mutex_exit(&connp->conn_lock);
+			}
+			break;	/* goto sizeof (int) option return */
+		case SO_MAC_EXEMPT:
+			if (secpolicy_net_mac_aware(cr) != 0 ||
+			    IPCL_IS_BOUND(connp))
+				return (EACCES);
+			if (!checkonly) {
+				mutex_enter(&connp->conn_lock);
+				connp->conn_mac_exempt = *i1 != 0 ? 1 : 0;
+				mutex_exit(&connp->conn_lock);
+			}
+			break;	/* goto sizeof (int) option return */
 		default:
 			/*
 			 * "soft" error (negative)
@@ -9674,7 +10031,7 @@
 			 * operation succeeds on at least one interface.
 			 */
 			ire = ire_ftable_lookup(group, IP_HOST_MASK, 0,
-			    IRE_HOST, NULL, NULL, ALL_ZONES, 0,
+			    IRE_HOST, NULL, NULL, ALL_ZONES, 0, NULL,
 			    MATCH_IRE_MASK | MATCH_IRE_TYPE);
 			if (ire != NULL) {
 				if (ire->ire_flags & RTF_MULTIRT) {
@@ -9782,7 +10139,7 @@
 			 * the request as noted in the mcast cases above.
 			 */
 			ire = ire_ftable_lookup(grp, IP_HOST_MASK, 0,
-			    IRE_HOST, NULL, NULL, ALL_ZONES, 0,
+			    IRE_HOST, NULL, NULL, ALL_ZONES, 0, NULL,
 			    MATCH_IRE_MASK | MATCH_IRE_TYPE);
 			if (ire != NULL) {
 				if (ire->ire_flags & RTF_MULTIRT) {
@@ -10008,7 +10365,7 @@
 			 * the operation succeeds on at least one interface.
 			 */
 			ire = ire_ftable_lookup_v6(&groupv6, &ipv6_all_ones, 0,
-			    IRE_HOST, NULL, NULL, ALL_ZONES, 0,
+			    IRE_HOST, NULL, NULL, ALL_ZONES, 0, NULL,
 			    MATCH_IRE_MASK | MATCH_IRE_TYPE);
 			if (ire != NULL) {
 				if (ire->ire_flags & RTF_MULTIRT) {
@@ -10094,7 +10451,7 @@
 			 * the request as noted in the mcast cases above.
 			 */
 			ire = ire_ftable_lookup_v6(&v6grp, &ipv6_all_ones, 0,
-			    IRE_HOST, NULL, NULL, ALL_ZONES, 0,
+			    IRE_HOST, NULL, NULL, ALL_ZONES, 0, NULL,
 			    MATCH_IRE_MASK | MATCH_IRE_TYPE);
 			if (ire != NULL) {
 				if (ire->ire_flags & RTF_MULTIRT) {
@@ -10218,7 +10575,7 @@
 			sin6 = (struct sockaddr_in6 *)invalp;
 			ire = ire_route_lookup_v6(&sin6->sin6_addr,
 			    0, 0, 0, NULL, NULL, connp->conn_zoneid,
-			    MATCH_IRE_DEFAULT);
+			    NULL, MATCH_IRE_DEFAULT);
 
 			if (ire == NULL) {
 				*outlenp = 0;
@@ -10353,7 +10710,7 @@
 	mtuinfo->ip6m_addr.sin6_port = port;
 	mtuinfo->ip6m_addr.sin6_addr = *in6;
 
-	ire = ire_cache_lookup_v6(in6, ALL_ZONES);
+	ire = ire_cache_lookup_v6(in6, ALL_ZONES, NULL);
 	if (ire != NULL) {
 		mtuinfo->ip6m_mtu = ire->ire_max_frag;
 		ire_refrele(ire);
@@ -12053,7 +12410,6 @@
 		first_mp = mp;
 	}
 
-tcp_slow:
 	/* Now we have a complete datagram, destined for this machine. */
 	u1 = ip_hdr_len = IPH_HDR_LENGTH(ipha);
 
@@ -12253,8 +12609,8 @@
 	IRE_REFRELE(ire);
 	IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst);
 	IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src);
-	if ((connp = sctp_find_conn(&map_src, &map_dst, ports, ipif_seqid,
-	    zoneid)) == NULL) {
+	if ((connp = sctp_fanout(&map_src, &map_dst, ports, ipif_seqid, zoneid,
+	    mp)) == NULL) {
 		/* Check for raw socket or OOTB handling */
 		goto no_conn;
 	}
@@ -12632,7 +12988,7 @@
 			src = ipha->ipha_src;
 			src_ire = ire_ftable_lookup(src, 0, 0,
 			    IRE_INTERFACE, ire->ire_ipif, NULL, ALL_ZONES,
-			    0, MATCH_IRE_IPIF | MATCH_IRE_TYPE);
+			    0, NULL, MATCH_IRE_IPIF | MATCH_IRE_TYPE);
 
 			if (src_ire != NULL) {
 				/*
@@ -12723,7 +13079,7 @@
 			return (B_TRUE);
 		}
 		new_ire = ire_ctable_lookup(dst, 0, 0,
-		    ipif, ALL_ZONES, MATCH_IRE_ILL);
+		    ipif, ALL_ZONES, NULL, MATCH_IRE_ILL);
 		ipif_refrele(ipif);
 
 		if (new_ire != NULL) {
@@ -13398,6 +13754,16 @@
 			continue;
 		}
 
+		/*
+		 * Attach any necessary label information to this packet.
+		 */
+		if (is_system_labeled() &&
+		    !tsol_get_pkt_label(mp, IPV4_VERSION)) {
+			BUMP_MIB(&ip_mib, ipInDiscards);
+			freemsg(mp);
+			continue;
+		}
+
 		opt_len = ipha->ipha_version_and_hdr_length -
 		    IP_SIMPLE_HDR_VERSION;
 		/* IP version bad or there are IP options */
@@ -13461,8 +13827,10 @@
 			}
 		}
 
-		if (ire == NULL)
-			ire = ire_cache_lookup(dst, ALL_ZONES);
+		if (ire == NULL) {
+			ire = ire_cache_lookup(dst, ALL_ZONES,
+			    MBLK_GETLABEL(mp));
+		}
 
 		/*
 		 * If mipagent is running and reverse tunnel is created as per
@@ -14927,6 +15295,19 @@
 	/* Get the ill_index of the outgoing ILL */
 	ill_index = ire->ire_ipif->ipif_ill->ill_phyint->phyint_ifindex;
 
+	if (is_system_labeled()) {
+		mblk_t *mp1;
+
+		if ((mp1 = tsol_ip_forward(ire, mp)) == NULL) {
+			BUMP_MIB(&ip_mib, ipForwProhibits);
+			goto drop_pkt;
+		}
+		/* Size may have changed */
+		mp = mp1;
+		ipha = (ipha_t *)mp->b_rptr;
+		pkt_len = ntohs(ipha->ipha_length);
+	}
+
 	/* Check if there are options to update */
 	if (!IS_SIMPLE_IPH(ipha)) {
 		if (ip_csum_hdr(ipha)) {
@@ -14999,9 +15380,9 @@
 	 */
 	if (ipif->ipif_flags & IPIF_POINTOPOINT)
 		dst = ipif->ipif_pp_dst_addr;
-	ire = ire_ctable_lookup(dst, 0, 0, ipif, ALL_ZONES,
-	    MATCH_IRE_ILL_GROUP);
-	if (!ire) {
+	ire = ire_ctable_lookup(dst, 0, 0, ipif, ALL_ZONES, MBLK_GETLABEL(mp),
+	    MATCH_IRE_ILL_GROUP | MATCH_IRE_SECATTR);
+	if (ire == NULL) {
 		/*
 		 * Mark this packet to make it be delivered to
 		 * ip_rput_forward after the new ire has been
@@ -15060,7 +15441,7 @@
 			}
 
 			dst_ire = ire_ctable_lookup(dst, 0, IRE_LOCAL,
-			    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+			    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (dst_ire == NULL) {
 				/*
 				 * Must be partial since ip_rput_options
@@ -15090,7 +15471,7 @@
 			 * once as consecutive hops in source route.
 			 */
 			tmp_ire = ire_ctable_lookup(dst, 0, IRE_LOCAL,
-			    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+			    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (tmp_ire != NULL) {
 				ire_refrele(tmp_ire);
 				off += IP_ADDR_LEN;
@@ -15127,7 +15508,9 @@
 				off = opt[IPOPT_OFFSET] - 1;
 				bcopy((char *)opt + off, &dst, IP_ADDR_LEN);
 				dst_ire = ire_ctable_lookup(dst, 0,
-				    IRE_LOCAL, NULL, ALL_ZONES, MATCH_IRE_TYPE);
+				    IRE_LOCAL, NULL, ALL_ZONES, NULL,
+				    MATCH_IRE_TYPE);
+
 				if (dst_ire == NULL) {
 					/* Not for us */
 					break;
@@ -15304,7 +15687,8 @@
 		}
 
 		if (ire == NULL) {
-			ire = ire_cache_lookup(dst, ii->ipsec_in_zoneid);
+			ire = ire_cache_lookup(dst, ii->ipsec_in_zoneid,
+			    MBLK_GETLABEL(mp));
 			if (ire == NULL) {
 				if (ill_need_rele)
 					ill_refrele(ill);
@@ -15621,6 +16005,7 @@
 				    ipha->ipha_dst != ilm->ilm_addr ||
 				    ilm->ilm_zoneid == last_zoneid ||
 				    ilm->ilm_zoneid == ire->ire_zoneid ||
+				    ilm->ilm_zoneid == ALL_ZONES ||
 				    !(ilm->ilm_ipif->ipif_flags & IPIF_UP))
 					continue;
 				mp1 = ip_copymsg(first_mp);
@@ -15676,6 +16061,12 @@
 			if (first_mp == NULL)
 				return;
 		}
+		if (is_system_labeled() && !tsol_can_accept_raw(mp, B_TRUE)) {
+			freemsg(first_mp);
+			ip1dbg(("ip_proto_input: zone all cannot accept raw"));
+			BUMP_MIB(&ip_mib, ipInDiscards);
+			return;
+		}
 		if (igmp_input(q, mp, ill)) {
 			/* Bad packet - discarded by igmp_input */
 			TRACE_2(TR_FAC_IP, TR_IP_RPUT_LOCL_END,
@@ -15706,6 +16097,12 @@
 			if (first_mp == NULL)
 				return;
 		}
+		if (is_system_labeled() && !tsol_can_accept_raw(mp, B_TRUE)) {
+			freemsg(first_mp);
+			ip1dbg(("ip_proto_input: zone all cannot accept PIM"));
+			BUMP_MIB(&ip_mib, ipInDiscards);
+			return;
+		}
 		if (pim_input(q, mp) != 0) {
 			/* Bad packet - discarded by pim_input */
 			TRACE_2(TR_FAC_IP, TR_IP_RPUT_LOCL_END,
@@ -15916,6 +16313,11 @@
 	default:
 		break;
 	}
+	if (is_system_labeled() && !tsol_can_accept_raw(mp, B_FALSE)) {
+		ip1dbg(("ip_proto_input: zone %d cannot accept raw IP",
+		    ire->ire_zoneid));
+		goto drop_pkt;
+	}
 	/*
 	 * Handle protocols with which IP is less intimate.  There
 	 * can be more than one stream bound to a particular
@@ -16027,7 +16429,7 @@
 				off = opt[IPOPT_OFFSET] - 1;
 				bcopy((char *)opt + off, &dst, IP_ADDR_LEN);
 				dst_ire = ire_ctable_lookup(dst, 0, IRE_LOCAL,
-				    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+				    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 				if (dst_ire == NULL) {
 					/* Not for us */
 					break;
@@ -16123,7 +16525,7 @@
 		case IPOPT_SSRR:
 		case IPOPT_LSRR:
 			ire = ire_ctable_lookup(dst, 0, IRE_LOCAL, NULL,
-			    ALL_ZONES, MATCH_IRE_TYPE);
+			    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (ire == NULL) {
 				if (optval == IPOPT_SSRR) {
 					ip1dbg(("ip_rput_options: not next"
@@ -16167,7 +16569,7 @@
 			 * for source route?
 			 */
 			ire = ire_ctable_lookup(dst, 0, IRE_LOCAL, NULL,
-			    ALL_ZONES, MATCH_IRE_TYPE);
+			    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 
 			if (ire != NULL) {
 				ire_refrele(ire);
@@ -16187,7 +16589,8 @@
 			if (optval == IPOPT_SSRR) {
 				ire = ire_ftable_lookup(dst, 0, 0,
 				    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0,
-				    MATCH_IRE_TYPE);
+				    MBLK_GETLABEL(mp),
+				    MATCH_IRE_TYPE | MATCH_IRE_SECATTR);
 				if (ire == NULL) {
 					ip1dbg(("ip_rput_options: SSRR not "
 					    "directly reachable: 0x%x\n",
@@ -16283,6 +16686,7 @@
  *  - ipAddrEntryTable (ip 20)		all IPv4 ipifs
  *  - ipRouteEntryTable (ip 21)		all IPv4 IREs
  *  - ipNetToMediaEntryTable (ip 22)	IPv4 IREs for on-link destinations
+ *  - ipRouteAttributeTable (ip 102)	labeled routes
  *  - ip multicast membership (ip_member_t)
  *  - ip multicast source filtering (ip_grpsrc_t)
  *  - igmp fixed part (struct igmpstat)
@@ -16294,6 +16698,7 @@
  *  - icmp6 fixed part (mib2_ipv6IfIcmpEntry_t)
  *					One per ill plus one generic
  *  - ipv6RouteEntry			all IPv6 IREs
+ *  - ipv6RouteAttributeTable (ip6 102)	labeled routes
  *  - ipv6NetToMediaEntry		all Neighbor Cache entries
  *  - ipv6AddrEntry			all IPv6 ipifs
  *  - ipv6 multicast membership (ipv6_member_t)
@@ -16301,8 +16706,8 @@
  *
  * IP_ROUTE and IP_MEDIA are augmented in arp to include arp cache entries not
  * already present.
- * NOTE: original mpctl is copied for msg's 2..N, since its ctl part
- * already filled in by caller.
+ * NOTE: original mpctl is copied for msg's 2..N, since its ctl part is
+ * already filled in by the caller.
  * Return value of 0 indicates that no messages were sent and caller
  * should free mpctl.
  */
@@ -16416,6 +16821,8 @@
 	    sizeof (mib2_ipNetToMediaEntry_t));
 	SET_MIB(ip_mib.ipMemberEntrySize, sizeof (ip_member_t));
 	SET_MIB(ip_mib.ipGroupSourceEntrySize, sizeof (ip_grpsrc_t));
+	SET_MIB(ip_mib.ipRouteAttributeSize, sizeof (mib2_ipAttributeEntry_t));
+	SET_MIB(ip_mib.transportMLPSize, sizeof (mib2_transportMLPEntry_t));
 	if (!snmp_append_data(mpctl->b_cont, (char *)&ip_mib,
 	    (int)sizeof (ip_mib))) {
 		ip1dbg(("ip_snmp_get_mib2_ip: failed to allocate %u bytes\n",
@@ -16539,7 +16946,8 @@
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		for (ipif = ill->ill_ipif; ipif != NULL;
 		    ipif = ipif->ipif_next) {
-			if (ipif->ipif_zoneid != zoneid)
+			if (ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			mae.ipAdEntInfo.ae_ibcnt = ipif->ipif_ib_pkt_count;
 			mae.ipAdEntInfo.ae_obcnt = ipif->ipif_ob_pkt_count;
@@ -16618,7 +17026,8 @@
 	ill = ILL_START_WALK_V6(&ctx);
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
-			if (ipif->ipif_zoneid != zoneid)
+			if (ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			mae6.ipv6AddrInfo.ae_ibcnt = ipif->ipif_ib_pkt_count;
 			mae6.ipv6AddrInfo.ae_obcnt = ipif->ipif_ob_pkt_count;
@@ -16714,7 +17123,8 @@
 		ILM_WALKER_HOLD(ill);
 		for (ipif = ill->ill_ipif; ipif != NULL;
 		    ipif = ipif->ipif_next) {
-			if (ipif->ipif_zoneid != zoneid)
+			if (ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;	/* not this zone */
 			(void) ipif_get_name(ipif,
 			    ipm.ipGroupMemberIfIndex.o_bytes,
@@ -16989,60 +17399,60 @@
 }
 
 /*
- * Return both ipRouteEntryTable, and ipNetToMediaEntryTable
+ * Return ipRouteEntryTable, ipNetToMediaEntryTable, and ipRouteAttributeTable
  * in one IRE walk.
  */
 static mblk_t *
 ip_snmp_get_mib2_ip_route_media(queue_t *q, mblk_t *mpctl)
 {
-	struct opthdr		*optp;
-	mblk_t			*mp2ctl;	/* Returned */
-	mblk_t			*mp3ctl;	/* nettomedia */
-	/*
-	 * We need two listptrs, for ipRouteEntryTable and
-	 * ipNetToMediaEntryTable to pass to ip_snmp_get2_v4()
-	 */
-	listptr_t		re_ntme_v4[2];
-	zoneid_t		zoneid;
-
-	/*
-	 * make a copy of the original message
+	struct opthdr	*optp;
+	mblk_t		*mp2ctl;	/* Returned */
+	mblk_t		*mp3ctl;	/* nettomedia */
+	mblk_t		*mp4ctl;	/* routeattrs */
+	iproutedata_t	ird;
+	zoneid_t	zoneid;
+
+	/*
+	 * make copies of the original message
+	 *	- mp2ctl is returned unchanged to the caller for his use
+	 *	- mpctl is sent upstream as ipRouteEntryTable
+	 *	- mp3ctl is sent upstream as ipNetToMediaEntryTable
+	 *	- mp4ctl is sent upstream as ipRouteAttributeTable
 	 */
 	mp2ctl = copymsg(mpctl);
 	mp3ctl = copymsg(mpctl);
-	if (mp3ctl == NULL) {
+	mp4ctl = copymsg(mpctl);
+	if (mp3ctl == NULL || mp4ctl == NULL) {
+		freemsg(mp4ctl);
+		freemsg(mp3ctl);
 		freemsg(mp2ctl);
 		freemsg(mpctl);
 		return (NULL);
 	}
 
-	re_ntme_v4[0].lp_head = mpctl->b_cont;	/* ipRouteEntryTable */
-	re_ntme_v4[1].lp_head = mp3ctl->b_cont;	/* ipNetToMediaEntryTable */
-	/*
-	 * We assign NULL to tail ptrs as snmp_append_data2() will assign
-	 * proper values when called.
-	 */
-	re_ntme_v4[0].lp_tail = NULL;
-	re_ntme_v4[1].lp_tail = NULL;
+	bzero(&ird, sizeof (ird));
+
+	ird.ird_route.lp_head = mpctl->b_cont;
+	ird.ird_netmedia.lp_head = mp3ctl->b_cont;
+	ird.ird_attrs.lp_head = mp4ctl->b_cont;
 
 	zoneid = Q_TO_CONN(q)->conn_zoneid;
-	ire_walk_v4(ip_snmp_get2_v4, (char *)re_ntme_v4, zoneid);
+	ire_walk_v4(ip_snmp_get2_v4, &ird, zoneid);
 	if (zoneid == GLOBAL_ZONEID) {
 		/*
 		 * Those IREs are used by Mobile-IP; since mipagent(1M) requires
 		 * the sys_net_config privilege, it can only run in the global
 		 * zone, so we don't display these IREs in the other zones.
 		 */
-		ire_walk_srcif_table_v4(ip_snmp_get2_v4, (char *)re_ntme_v4);
-		ire_walk_ill_mrtun(0, 0, ip_snmp_get2_v4, (char *)re_ntme_v4,
-		    NULL);
+		ire_walk_srcif_table_v4(ip_snmp_get2_v4, &ird);
+		ire_walk_ill_mrtun(0, 0, ip_snmp_get2_v4, &ird, NULL);
 	}
 
 	/* ipRouteEntryTable in mpctl */
 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_IP;
 	optp->name = MIB2_IP_ROUTE;
-	optp->len = (t_uscalar_t)msgdsize(re_ntme_v4[0].lp_head);
+	optp->len = msgdsize(ird.ird_route.lp_head);
 	ip3dbg(("ip_snmp_get_mib2_ip_route_media: level %d, name %d, len %d\n",
 	    (int)optp->level, (int)optp->name, (int)optp->len));
 	qreply(q, mpctl);
@@ -17051,67 +17461,98 @@
 	optp = (struct opthdr *)&mp3ctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_IP;
 	optp->name = MIB2_IP_MEDIA;
-	optp->len = (t_uscalar_t)msgdsize(re_ntme_v4[1].lp_head);
+	optp->len = msgdsize(ird.ird_netmedia.lp_head);
 	ip3dbg(("ip_snmp_get_mib2_ip_route_media: level %d, name %d, len %d\n",
 	    (int)optp->level, (int)optp->name, (int)optp->len));
 	qreply(q, mp3ctl);
+
+	/* ipRouteAttributeTable in mp4ctl */
+	optp = (struct opthdr *)&mp4ctl->b_rptr[sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_IP;
+	optp->name = EXPER_IP_RTATTR;
+	optp->len = msgdsize(ird.ird_attrs.lp_head);
+	ip3dbg(("ip_snmp_get_mib2_ip_route_media: level %d, name %d, len %d\n",
+	    (int)optp->level, (int)optp->name, (int)optp->len));
+	if (optp->len == 0)
+		freemsg(mp4ctl);
+	else
+		qreply(q, mp4ctl);
+
 	return (mp2ctl);
 }
 
 /*
- * Return both ipv6RouteEntryTable, and ipv6NetToMediaEntryTable
- * in one IRE walk.
+ * Return ipv6RouteEntryTable and ipv6RouteAttributeTable in one IRE walk, and
+ * ipv6NetToMediaEntryTable in an NDP walk.
  */
 static mblk_t *
 ip_snmp_get_mib2_ip6_route_media(queue_t *q, mblk_t *mpctl)
 {
-	struct opthdr		*optp;
-	mblk_t			*mp2ctl;	/* Returned */
-	mblk_t			*mp3ctl;	/* nettomedia */
-	listptr_t		re_ntme_v6;
-	zoneid_t		zoneid;
-
-	/*
-	 * make a copy of the original message
+	struct opthdr	*optp;
+	mblk_t		*mp2ctl;	/* Returned */
+	mblk_t		*mp3ctl;	/* nettomedia */
+	mblk_t		*mp4ctl;	/* routeattrs */
+	iproutedata_t	ird;
+	zoneid_t	zoneid;
+
+	/*
+	 * make copies of the original message
+	 *	- mp2ctl is returned unchanged to the caller for his use
+	 *	- mpctl is sent upstream as ipv6RouteEntryTable
+	 *	- mp3ctl is sent upstream as ipv6NetToMediaEntryTable
+	 *	- mp4ctl is sent upstream as ipv6RouteAttributeTable
 	 */
 	mp2ctl = copymsg(mpctl);
 	mp3ctl = copymsg(mpctl);
-	if (mp3ctl == NULL) {
+	mp4ctl = copymsg(mpctl);
+	if (mp3ctl == NULL || mp4ctl == NULL) {
+		freemsg(mp4ctl);
+		freemsg(mp3ctl);
 		freemsg(mp2ctl);
 		freemsg(mpctl);
 		return (NULL);
 	}
 
-	/*
-	 * We assign NULL to tail ptrs as snmp_append_data2() will assign
-	 * proper values when called.  ipv6RouteEntryTable in is placed
-	 * in mpctl.
-	 */
-	re_ntme_v6.lp_head = mpctl->b_cont;	/* ip6RouteEntryTable */
-	re_ntme_v6.lp_tail = NULL;
+	bzero(&ird, sizeof (ird));
+
+	ird.ird_route.lp_head = mpctl->b_cont;
+	ird.ird_netmedia.lp_head = mp3ctl->b_cont;
+	ird.ird_attrs.lp_head = mp4ctl->b_cont;
+
 	zoneid = Q_TO_CONN(q)->conn_zoneid;
-	ire_walk_v6(ip_snmp_get2_v6_route, (char *)&re_ntme_v6, zoneid);
+	ire_walk_v6(ip_snmp_get2_v6_route, &ird, zoneid);
 
 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_IP6;
 	optp->name = MIB2_IP6_ROUTE;
-	optp->len = (t_uscalar_t)msgdsize(re_ntme_v6.lp_head);
+	optp->len = msgdsize(ird.ird_route.lp_head);
 	ip3dbg(("ip_snmp_get_mib2_ip6_route_media: level %d, name %d, len %d\n",
 	    (int)optp->level, (int)optp->name, (int)optp->len));
 	qreply(q, mpctl);
 
 	/* ipv6NetToMediaEntryTable in mp3ctl */
-	re_ntme_v6.lp_head = mp3ctl->b_cont;	/* ip6NetToMediaEntryTable */
-	re_ntme_v6.lp_tail = NULL;
-	ndp_walk(NULL, ip_snmp_get2_v6_media, (uchar_t *)&re_ntme_v6);
+	ndp_walk(NULL, ip_snmp_get2_v6_media, &ird);
 
 	optp = (struct opthdr *)&mp3ctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_IP6;
 	optp->name = MIB2_IP6_MEDIA;
-	optp->len = (t_uscalar_t)msgdsize(re_ntme_v6.lp_head);
+	optp->len = msgdsize(ird.ird_netmedia.lp_head);
 	ip3dbg(("ip_snmp_get_mib2_ip6_route_media: level %d, name %d, len %d\n",
 	    (int)optp->level, (int)optp->name, (int)optp->len));
 	qreply(q, mp3ctl);
+
+	/* ipv6RouteAttributeTable in mp4ctl */
+	optp = (struct opthdr *)&mp4ctl->b_rptr[sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_IP6;
+	optp->name = EXPER_IP_RTATTR;
+	optp->len = msgdsize(ird.ird_attrs.lp_head);
+	ip3dbg(("ip_snmp_get_mib2_ip6_route_media: level %d, name %d, len %d\n",
+	    (int)optp->level, (int)optp->name, (int)optp->len));
+	if (optp->len == 0)
+		freemsg(mp4ctl);
+	else
+		qreply(q, mp4ctl);
+
 	return (mp2ctl);
 }
 
@@ -17251,85 +17692,144 @@
  * ipNetToMediaEntryTable in one IRE walk
  */
 static void
-ip_snmp_get2_v4(ire_t *ire, listptr_t re_ntme[])
+ip_snmp_get2_v4(ire_t *ire, iproutedata_t *ird)
 {
 	ill_t				*ill;
 	ipif_t				*ipif;
 	mblk_t				*llmp;
 	dl_unitdata_req_t		*dlup;
-	mib2_ipRouteEntry_t		re;
+	mib2_ipRouteEntry_t		*re;
 	mib2_ipNetToMediaEntry_t	ntme;
+	mib2_ipAttributeEntry_t		*iae, *iaeptr;
 	ipaddr_t			gw_addr;
+	tsol_ire_gw_secattr_t		*attrp;
+	tsol_gc_t			*gc = NULL;
+	tsol_gcgrp_t			*gcgrp = NULL;
+	uint_t				sacnt = 0;
+	int				i;
 
 	ASSERT(ire->ire_ipversion == IPV4_VERSION);
 
+	if ((re = kmem_zalloc(sizeof (*re), KM_NOSLEEP)) == NULL)
+		return;
+
+	if ((attrp = ire->ire_gw_secattr) != NULL) {
+		mutex_enter(&attrp->igsa_lock);
+		if ((gc = attrp->igsa_gc) != NULL) {
+			gcgrp = gc->gc_grp;
+			ASSERT(gcgrp != NULL);
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			sacnt = 1;
+		} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			gc = gcgrp->gcgrp_head;
+			sacnt = gcgrp->gcgrp_count;
+		}
+		mutex_exit(&attrp->igsa_lock);
+
+		/* do nothing if there's no gc to report */
+		if (gc == NULL) {
+			ASSERT(sacnt == 0);
+			if (gcgrp != NULL) {
+				/* we might as well drop the lock now */
+				rw_exit(&gcgrp->gcgrp_rwlock);
+				gcgrp = NULL;
+			}
+			attrp = NULL;
+		}
+
+		ASSERT(gc == NULL || (gcgrp != NULL &&
+		    RW_LOCK_HELD(&gcgrp->gcgrp_rwlock)));
+	}
+	ASSERT(sacnt == 0 || gc != NULL);
+
+	if (sacnt != 0 &&
+	    (iae = kmem_alloc(sacnt * sizeof (*iae), KM_NOSLEEP)) == NULL) {
+		kmem_free(re, sizeof (*re));
+		rw_exit(&gcgrp->gcgrp_rwlock);
+		return;
+	}
+
 	/*
 	 * Return all IRE types for route table... let caller pick and choose
 	 */
-	re.ipRouteDest = ire->ire_addr;
+	re->ipRouteDest = ire->ire_addr;
 	ipif = ire->ire_ipif;
-	re.ipRouteIfIndex.o_length = 0;
+	re->ipRouteIfIndex.o_length = 0;
 	if (ire->ire_type == IRE_CACHE) {
 		ill = (ill_t *)ire->ire_stq->q_ptr;
-		re.ipRouteIfIndex.o_length =
+		re->ipRouteIfIndex.o_length =
 		    ill->ill_name_length == 0 ? 0 :
 		    MIN(OCTET_LENGTH, ill->ill_name_length - 1);
-		bcopy(ill->ill_name, re.ipRouteIfIndex.o_bytes,
-		    re.ipRouteIfIndex.o_length);
+		bcopy(ill->ill_name, re->ipRouteIfIndex.o_bytes,
+		    re->ipRouteIfIndex.o_length);
 	} else if (ipif != NULL) {
-		(void) ipif_get_name(ipif, re.ipRouteIfIndex.o_bytes,
+		(void) ipif_get_name(ipif, re->ipRouteIfIndex.o_bytes,
 		    OCTET_LENGTH);
-		re.ipRouteIfIndex.o_length =
-		    mi_strlen(re.ipRouteIfIndex.o_bytes);
-	}
-	re.ipRouteMetric1 = -1;
-	re.ipRouteMetric2 = -1;
-	re.ipRouteMetric3 = -1;
-	re.ipRouteMetric4 = -1;
+		re->ipRouteIfIndex.o_length =
+		    mi_strlen(re->ipRouteIfIndex.o_bytes);
+	}
+	re->ipRouteMetric1 = -1;
+	re->ipRouteMetric2 = -1;
+	re->ipRouteMetric3 = -1;
+	re->ipRouteMetric4 = -1;
 
 	gw_addr = ire->ire_gateway_addr;
 
 	if (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST))
-		re.ipRouteNextHop = ire->ire_src_addr;
+		re->ipRouteNextHop = ire->ire_src_addr;
 	else
-		re.ipRouteNextHop = gw_addr;
+		re->ipRouteNextHop = gw_addr;
 	/* indirect(4), direct(3), or invalid(2) */
 	if (ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))
-		re.ipRouteType = 2;
+		re->ipRouteType = 2;
 	else
-		re.ipRouteType = (gw_addr != 0) ? 4 : 3;
-	re.ipRouteProto = -1;
-	re.ipRouteAge = gethrestime_sec() - ire->ire_create_time;
-	re.ipRouteMask = ire->ire_mask;
-	re.ipRouteMetric5 = -1;
-	re.ipRouteInfo.re_max_frag  = ire->ire_max_frag;
-	re.ipRouteInfo.re_frag_flag = ire->ire_frag_flag;
-	re.ipRouteInfo.re_rtt	    = ire->ire_uinfo.iulp_rtt;
+		re->ipRouteType = (gw_addr != 0) ? 4 : 3;
+	re->ipRouteProto = -1;
+	re->ipRouteAge = gethrestime_sec() - ire->ire_create_time;
+	re->ipRouteMask = ire->ire_mask;
+	re->ipRouteMetric5 = -1;
+	re->ipRouteInfo.re_max_frag	= ire->ire_max_frag;
+	re->ipRouteInfo.re_frag_flag	= ire->ire_frag_flag;
+	re->ipRouteInfo.re_rtt		= ire->ire_uinfo.iulp_rtt;
 	llmp = ire->ire_dlureq_mp;
-	re.ipRouteInfo.re_ref	    = ire->ire_refcnt;
-	re.ipRouteInfo.re_src_addr  = ire->ire_src_addr;
-	re.ipRouteInfo.re_ire_type  = ire->ire_type;
-	re.ipRouteInfo.re_obpkt	    = ire->ire_ob_pkt_count;
-	re.ipRouteInfo.re_ibpkt	    = ire->ire_ib_pkt_count;
-	re.ipRouteInfo.re_flags	    = ire->ire_flags;
-	re.ipRouteInfo.re_in_ill.o_length = 0;
+	re->ipRouteInfo.re_ref		= ire->ire_refcnt;
+	re->ipRouteInfo.re_src_addr	= ire->ire_src_addr;
+	re->ipRouteInfo.re_ire_type	= ire->ire_type;
+	re->ipRouteInfo.re_obpkt	= ire->ire_ob_pkt_count;
+	re->ipRouteInfo.re_ibpkt	= ire->ire_ib_pkt_count;
+	re->ipRouteInfo.re_flags	= ire->ire_flags;
+	re->ipRouteInfo.re_in_ill.o_length = 0;
 	if (ire->ire_in_ill != NULL) {
-		re.ipRouteInfo.re_in_ill.o_length =
+		re->ipRouteInfo.re_in_ill.o_length =
 		    ire->ire_in_ill->ill_name_length == 0 ? 0 :
 		    MIN(OCTET_LENGTH, ire->ire_in_ill->ill_name_length - 1);
 		bcopy(ire->ire_in_ill->ill_name,
-		    re.ipRouteInfo.re_in_ill.o_bytes,
-		    re.ipRouteInfo.re_in_ill.o_length);
-	}
-	re.ipRouteInfo.re_in_src_addr = ire->ire_in_src_addr;
-	if (!snmp_append_data2(re_ntme[0].lp_head, &(re_ntme[0].lp_tail),
-	    (char *)&re, (int)sizeof (re))) {
+		    re->ipRouteInfo.re_in_ill.o_bytes,
+		    re->ipRouteInfo.re_in_ill.o_length);
+	}
+	re->ipRouteInfo.re_in_src_addr = ire->ire_in_src_addr;
+
+	if (!snmp_append_data2(ird->ird_route.lp_head, &ird->ird_route.lp_tail,
+	    (char *)re, (int)sizeof (*re))) {
 		ip1dbg(("ip_snmp_get2_v4: failed to allocate %u bytes\n",
-		    (uint_t)sizeof (re)));
+		    (uint_t)sizeof (*re)));
+	}
+
+	for (iaeptr = iae, i = 0; i < sacnt; i++, iaeptr++, gc = gc->gc_next) {
+		iaeptr->iae_routeidx = ird->ird_idx;
+		iaeptr->iae_doi = gc->gc_db->gcdb_doi;
+		iaeptr->iae_slrange = gc->gc_db->gcdb_slrange;
+	}
+
+	if (!snmp_append_data2(ird->ird_attrs.lp_head, &ird->ird_attrs.lp_tail,
+	    (char *)iae, sacnt * sizeof (*iae))) {
+		ip1dbg(("ip_snmp_get2_v4: failed to allocate %u bytes\n",
+		    (unsigned)(sacnt * sizeof (*iae))));
 	}
 
 	if (ire->ire_type != IRE_CACHE || gw_addr != 0)
-		return;
+		goto done;
 	/*
 	 * only IRE_CACHE entries that are for a directly connected subnet
 	 * get appended to net -> phys addr table
@@ -17368,46 +17868,102 @@
 	bcopy(&ire->ire_mask, ntme.ipNetToMediaInfo.ntm_mask.o_bytes,
 	    ntme.ipNetToMediaInfo.ntm_mask.o_length);
 	ntme.ipNetToMediaInfo.ntm_flags = ACE_F_RESOLVED;
-	if (!snmp_append_data2(re_ntme[1].lp_head, &(re_ntme[1].lp_tail),
-	    (char *)&ntme, (int)sizeof (ntme))) {
+	if (!snmp_append_data2(ird->ird_netmedia.lp_head,
+	    &ird->ird_netmedia.lp_tail, (char *)&ntme, sizeof (ntme))) {
 		ip1dbg(("ip_snmp_get2_v4: failed to allocate %u bytes\n",
 		    (uint_t)sizeof (ntme)));
 	}
-}
-
-/*
- * ire_walk routine to create ipv6RouteEntryTable.
- */
-static void
-ip_snmp_get2_v6_route(ire_t *ire, listptr_t *re_ntme)
+done:
+	/* bump route index for next pass */
+	ird->ird_idx++;
+
+	kmem_free(re, sizeof (*re));
+	if (sacnt != 0)
+		kmem_free(iae, sacnt * sizeof (*iae));
+
+	if (gcgrp != NULL)
+		rw_exit(&gcgrp->gcgrp_rwlock);
+}
+
+/*
+ * ire_walk routine to create ipv6RouteEntryTable and ipRouteEntryTable.
+ */
+static void
+ip_snmp_get2_v6_route(ire_t *ire, iproutedata_t *ird)
 {
 	ill_t				*ill;
 	ipif_t				*ipif;
-	mib2_ipv6RouteEntry_t		re;
+	mib2_ipv6RouteEntry_t		*re;
+	mib2_ipAttributeEntry_t		*iae, *iaeptr;
 	in6_addr_t			gw_addr_v6;
+	tsol_ire_gw_secattr_t		*attrp;
+	tsol_gc_t			*gc = NULL;
+	tsol_gcgrp_t			*gcgrp = NULL;
+	uint_t				sacnt = 0;
+	int				i;
 
 	ASSERT(ire->ire_ipversion == IPV6_VERSION);
 
+	if ((re = kmem_zalloc(sizeof (*re), KM_NOSLEEP)) == NULL)
+		return;
+
+	if ((attrp = ire->ire_gw_secattr) != NULL) {
+		mutex_enter(&attrp->igsa_lock);
+		if ((gc = attrp->igsa_gc) != NULL) {
+			gcgrp = gc->gc_grp;
+			ASSERT(gcgrp != NULL);
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			sacnt = 1;
+		} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			gc = gcgrp->gcgrp_head;
+			sacnt = gcgrp->gcgrp_count;
+		}
+		mutex_exit(&attrp->igsa_lock);
+
+		/* do nothing if there's no gc to report */
+		if (gc == NULL) {
+			ASSERT(sacnt == 0);
+			if (gcgrp != NULL) {
+				/* we might as well drop the lock now */
+				rw_exit(&gcgrp->gcgrp_rwlock);
+				gcgrp = NULL;
+			}
+			attrp = NULL;
+		}
+
+		ASSERT(gc == NULL || (gcgrp != NULL &&
+		    RW_LOCK_HELD(&gcgrp->gcgrp_rwlock)));
+	}
+	ASSERT(sacnt == 0 || gc != NULL);
+
+	if (sacnt != 0 &&
+	    (iae = kmem_alloc(sacnt * sizeof (*iae), KM_NOSLEEP)) == NULL) {
+		kmem_free(re, sizeof (*re));
+		rw_exit(&gcgrp->gcgrp_rwlock);
+		return;
+	}
+
 	/*
 	 * Return all IRE types for route table... let caller pick and choose
 	 */
-	re.ipv6RouteDest = ire->ire_addr_v6;
-	re.ipv6RoutePfxLength = ip_mask_to_plen_v6(&ire->ire_mask_v6);
-	re.ipv6RouteIndex = 0;	/* Unique when multiple with same dest/plen */
-	re.ipv6RouteIfIndex.o_length = 0;
+	re->ipv6RouteDest = ire->ire_addr_v6;
+	re->ipv6RoutePfxLength = ip_mask_to_plen_v6(&ire->ire_mask_v6);
+	re->ipv6RouteIndex = 0;	/* Unique when multiple with same dest/plen */
+	re->ipv6RouteIfIndex.o_length = 0;
 	ipif = ire->ire_ipif;
 	if (ire->ire_type == IRE_CACHE) {
 		ill = (ill_t *)ire->ire_stq->q_ptr;
-		re.ipv6RouteIfIndex.o_length =
+		re->ipv6RouteIfIndex.o_length =
 		    ill->ill_name_length == 0 ? 0 :
 		    MIN(OCTET_LENGTH, ill->ill_name_length - 1);
-		bcopy(ill->ill_name, re.ipv6RouteIfIndex.o_bytes,
-		    re.ipv6RouteIfIndex.o_length);
+		bcopy(ill->ill_name, re->ipv6RouteIfIndex.o_bytes,
+		    re->ipv6RouteIfIndex.o_length);
 	} else if (ipif != NULL) {
-		(void) ipif_get_name(ipif, re.ipv6RouteIfIndex.o_bytes,
+		(void) ipif_get_name(ipif, re->ipv6RouteIfIndex.o_bytes,
 		    OCTET_LENGTH);
-		re.ipv6RouteIfIndex.o_length =
-		    mi_strlen(re.ipv6RouteIfIndex.o_bytes);
+		re->ipv6RouteIfIndex.o_length =
+		    mi_strlen(re->ipv6RouteIfIndex.o_bytes);
 	}
 
 	ASSERT(!(ire->ire_type & IRE_BROADCAST));
@@ -17417,46 +17973,68 @@
 	mutex_exit(&ire->ire_lock);
 
 	if (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK))
-		re.ipv6RouteNextHop = ire->ire_src_addr_v6;
+		re->ipv6RouteNextHop = ire->ire_src_addr_v6;
 	else
-		re.ipv6RouteNextHop = gw_addr_v6;
+		re->ipv6RouteNextHop = gw_addr_v6;
 
 	/* remote(4), local(3), or discard(2) */
 	if (ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))
-		re.ipv6RouteType = 2;
+		re->ipv6RouteType = 2;
 	else if (IN6_IS_ADDR_UNSPECIFIED(&gw_addr_v6))
-		re.ipv6RouteType = 3;
+		re->ipv6RouteType = 3;
 	else
-		re.ipv6RouteType = 4;
-
-	re.ipv6RouteProtocol		= -1;
-	re.ipv6RoutePolicy		= 0;
-	re.ipv6RouteAge		= gethrestime_sec() - ire->ire_create_time;
-	re.ipv6RouteNextHopRDI		= 0;
-	re.ipv6RouteWeight		= 0;
-	re.ipv6RouteMetric		= 0;
-	re.ipv6RouteInfo.re_max_frag	= ire->ire_max_frag;
-	re.ipv6RouteInfo.re_frag_flag	= ire->ire_frag_flag;
-	re.ipv6RouteInfo.re_rtt		= ire->ire_uinfo.iulp_rtt;
-	re.ipv6RouteInfo.re_src_addr	= ire->ire_src_addr_v6;
-	re.ipv6RouteInfo.re_ire_type	= ire->ire_type;
-	re.ipv6RouteInfo.re_obpkt	= ire->ire_ob_pkt_count;
-	re.ipv6RouteInfo.re_ibpkt	= ire->ire_ib_pkt_count;
-	re.ipv6RouteInfo.re_ref		= ire->ire_refcnt;
-	re.ipv6RouteInfo.re_flags	= ire->ire_flags;
-
-	if (!snmp_append_data2(re_ntme->lp_head, &(re_ntme->lp_tail),
-	    (char *)&re, (int)sizeof (re))) {
+		re->ipv6RouteType = 4;
+
+	re->ipv6RouteProtocol	= -1;
+	re->ipv6RoutePolicy	= 0;
+	re->ipv6RouteAge	= gethrestime_sec() - ire->ire_create_time;
+	re->ipv6RouteNextHopRDI	= 0;
+	re->ipv6RouteWeight	= 0;
+	re->ipv6RouteMetric	= 0;
+	re->ipv6RouteInfo.re_max_frag	= ire->ire_max_frag;
+	re->ipv6RouteInfo.re_frag_flag	= ire->ire_frag_flag;
+	re->ipv6RouteInfo.re_rtt	= ire->ire_uinfo.iulp_rtt;
+	re->ipv6RouteInfo.re_src_addr	= ire->ire_src_addr_v6;
+	re->ipv6RouteInfo.re_ire_type	= ire->ire_type;
+	re->ipv6RouteInfo.re_obpkt	= ire->ire_ob_pkt_count;
+	re->ipv6RouteInfo.re_ibpkt	= ire->ire_ib_pkt_count;
+	re->ipv6RouteInfo.re_ref	= ire->ire_refcnt;
+	re->ipv6RouteInfo.re_flags	= ire->ire_flags;
+
+	if (!snmp_append_data2(ird->ird_route.lp_head, &ird->ird_route.lp_tail,
+	    (char *)re, (int)sizeof (*re))) {
 		ip1dbg(("ip_snmp_get2_v6: failed to allocate %u bytes\n",
-		    (uint_t)sizeof (re)));
-	}
+		    (uint_t)sizeof (*re)));
+	}
+
+	for (iaeptr = iae, i = 0; i < sacnt; i++, iaeptr++, gc = gc->gc_next) {
+		iaeptr->iae_routeidx = ird->ird_idx;
+		iaeptr->iae_doi = gc->gc_db->gcdb_doi;
+		iaeptr->iae_slrange = gc->gc_db->gcdb_slrange;
+	}
+
+	if (!snmp_append_data2(ird->ird_attrs.lp_head, &ird->ird_attrs.lp_tail,
+	    (char *)iae, sacnt * sizeof (*iae))) {
+		ip1dbg(("ip_snmp_get2_v6: failed to allocate %u bytes\n",
+		    (unsigned)(sacnt * sizeof (*iae))));
+	}
+
+	/* bump route index for next pass */
+	ird->ird_idx++;
+
+	kmem_free(re, sizeof (*re));
+	if (sacnt != 0)
+		kmem_free(iae, sacnt * sizeof (*iae));
+
+	if (gcgrp != NULL)
+		rw_exit(&gcgrp->gcgrp_rwlock);
 }
 
 /*
  * ndp_walk routine to create ipv6NetToMediaEntryTable
  */
 static int
-ip_snmp_get2_v6_media(nce_t *nce, listptr_t *re_ntme)
+ip_snmp_get2_v6_media(nce_t *nce, iproutedata_t *ird)
 {
 	ill_t				*ill;
 	mib2_ipv6NetToMediaEntry_t	ntme;
@@ -17506,8 +18084,8 @@
 		ntme.ipv6NetToMediaType = 2;
 	}
 
-	if (!snmp_append_data2(re_ntme->lp_head,
-	    &(re_ntme->lp_tail), (char *)&ntme, (int)sizeof (ntme))) {
+	if (!snmp_append_data2(ird->ird_netmedia.lp_head,
+	    &ird->ird_netmedia.lp_tail, (char *)&ntme, sizeof (ntme))) {
 		ip1dbg(("ip_snmp_get2_v6_media: failed to allocate %u bytes\n",
 		    (uint_t)sizeof (ntme)));
 	}
@@ -17572,7 +18150,7 @@
 			 * entries left in the source route return (true).
 			 */
 			ire = ire_ctable_lookup(dst, 0, IRE_LOCAL, NULL,
-			    ALL_ZONES, MATCH_IRE_TYPE);
+			    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (ire == NULL) {
 				ip2dbg(("ip_source_routed: not next"
 				    " source route 0x%x\n",
@@ -17820,6 +18398,14 @@
 
 	ASSERT(!MUTEX_HELD(&connp->conn_lock));
 
+	if (is_system_labeled() && connp->conn_anon_port) {
+		(void) tsol_mlp_anon(crgetzone(connp->conn_cred),
+		    connp->conn_mlp_type, connp->conn_ulp,
+		    ntohs(connp->conn_lport), B_FALSE);
+		connp->conn_anon_port = 0;
+	}
+	connp->conn_mlp_type = mlptSingle;
+
 	ipcl_hash_remove(connp);
 
 	ASSERT(mp->b_cont == NULL);
@@ -17873,6 +18459,8 @@
 	mblk_t		*copy_mp = NULL;
 	int		err;
 	zoneid_t	zoneid;
+	int	adjust;
+	uint16_t iplen;
 	boolean_t	need_decref = B_FALSE;
 	boolean_t	ignore_dontroute = B_FALSE;
 	boolean_t	ignore_nexthop = B_FALSE;
@@ -17919,6 +18507,7 @@
 		return;
 	} else if (DB_TYPE(mp) != M_DATA)
 		goto notdata;
+
 	if (mp->b_flag & MSGHASREF) {
 		ASSERT(connp->conn_ulp == IPPROTO_SCTP);
 		mp->b_flag &= ~MSGHASREF;
@@ -17934,6 +18523,34 @@
 		goto hdrtoosmall;
 #endif
 
+	ASSERT(OK_32PTR(ipha));
+
+	/*
+	 * This function assumes that mp points to an IPv4 packet.  If it's the
+	 * wrong version, we'll catch it again in ip_output_v6.
+	 *
+	 * Note that this is *only* locally-generated output here, and never
+	 * forwarded data, and that we need to deal only with transports that
+	 * don't know how to label.  (TCP, UDP, and ICMP/raw-IP all know how to
+	 * label.)
+	 */
+	if (is_system_labeled() &&
+	    (ipha->ipha_version_and_hdr_length & 0xf0) == (IPV4_VERSION << 4) &&
+	    !connp->conn_ulp_labeled) {
+		err = tsol_check_label(BEST_CRED(mp, connp), &mp, &adjust,
+		    connp->conn_mac_exempt);
+		ipha = (ipha_t *)mp->b_rptr;
+		if (err != 0) {
+			first_mp = mp;
+			if (err == EINVAL)
+				goto icmp_parameter_problem;
+			ip2dbg(("ip_wput: label check failed (%d)\n", err));
+			goto drop_pkt;
+		}
+		iplen = ntohs(ipha->ipha_length) + adjust;
+		ipha->ipha_length = htons(iplen);
+	}
+
 	/*
 	 * If there is a policy, try to attach an ipsec_out in
 	 * the front. At the end, first_mp either points to a
@@ -17989,7 +18606,7 @@
 		 * destination only SO_DONTROUTE and IP_NEXTHOP go through
 		 * the standard path not IP_XMIT_IF.
 		 */
-		ire = ire_cache_lookup(dst, zoneid);
+		ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp));
 		if ((ire == NULL) || ((ire->ire_type != IRE_BROADCAST) &&
 		    (ire->ire_type != IRE_LOOPBACK))) {
 			if ((connp->conn_dontroute ||
@@ -18055,7 +18672,7 @@
 	 */
 	if (IP_FLOW_CONTROLLED_ULP(connp->conn_ulp) &&
 	    !connp->conn_fully_bound) {
-		ire = ire_cache_lookup(dst, zoneid);
+		ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp));
 		if (ire == NULL)
 			goto noirefound;
 		TRACE_2(TR_FAC_IP, TR_IP_WPUT_END,
@@ -18091,7 +18708,8 @@
 			 * to initiate additional route resolutions.
 			 */
 			multirt_need_resolve =
-			    ire_multirt_need_resolve(ire->ire_addr);
+			    ire_multirt_need_resolve(ire->ire_addr,
+			    MBLK_GETLABEL(first_mp));
 			ip2dbg(("ip_wput[TCP]: ire %p, "
 			    "multirt_need_resolve %d, first_mp %p\n",
 			    (void *)ire, multirt_need_resolve,
@@ -18161,7 +18779,7 @@
 		if (ire != NULL && sctp_ire == NULL)
 			IRE_REFRELE_NOTR(ire);
 
-		ire = (ire_t *)ire_cache_lookup(dst, zoneid);
+		ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp));
 		if (ire == NULL)
 			goto noirefound;
 		IRE_REFHOLD_NOTR(ire);
@@ -18220,7 +18838,8 @@
 		 * of the current message. It will be used
 		 * to initiate additional route resolutions.
 		 */
-		multirt_need_resolve = ire_multirt_need_resolve(ire->ire_addr);
+		multirt_need_resolve = ire_multirt_need_resolve(ire->ire_addr,
+		    MBLK_GETLABEL(first_mp));
 		ip2dbg(("ip_wput[not TCP]: ire %p, "
 		    "multirt_need_resolve %d, first_mp %p\n",
 		    (void *)ire, multirt_need_resolve, (void *)first_mp));
@@ -18330,7 +18949,7 @@
 				return;
 			} else {
 				/*
-				 * This must be ARP.
+				 * This must be ARP or special TSOL signaling.
 				 */
 				ip_wput_nondata(NULL, q, mp, NULL);
 				TRACE_2(TR_FAC_IP, TR_IP_WPUT_END,
@@ -18452,6 +19071,29 @@
 				first_mp = mp;
 			goto drop_pkt;
 		}
+
+		/* This function assumes that mp points to an IPv4 packet. */
+		if (is_system_labeled() && q->q_next == NULL &&
+		    (*mp->b_rptr & 0xf0) == (IPV4_VERSION << 4) &&
+		    !connp->conn_ulp_labeled) {
+			err = tsol_check_label(BEST_CRED(mp, connp), &mp,
+			    &adjust, connp->conn_mac_exempt);
+			ipha = (ipha_t *)mp->b_rptr;
+			if (first_mp != NULL)
+				first_mp->b_cont = mp;
+			if (err != 0) {
+				if (first_mp == NULL)
+					first_mp = mp;
+				if (err == EINVAL)
+					goto icmp_parameter_problem;
+				ip2dbg(("ip_wput: label check failed (%d)\n",
+				    err));
+				goto drop_pkt;
+			}
+			iplen = ntohs(ipha->ipha_length) + adjust;
+			ipha->ipha_length = htons(iplen);
+		}
+
 		ipha = (ipha_t *)mp->b_rptr;
 		if (first_mp == NULL) {
 			ASSERT(attach_ill == NULL && xmit_ill == NULL);
@@ -18717,7 +19359,7 @@
 		}
 		if (attach_ill != NULL) {
 			ASSERT(attach_ill == ipif->ipif_ill);
-			match_flags = MATCH_IRE_ILL;
+			match_flags = MATCH_IRE_ILL | MATCH_IRE_SECATTR;
 
 			/*
 			 * Check if we need an ire that will not be
@@ -18730,7 +19372,7 @@
 			    attach_ill->ill_phyint->phyint_ifindex;
 			io->ipsec_out_attach_if = B_TRUE;
 		} else {
-			match_flags = MATCH_IRE_ILL_GROUP;
+			match_flags = MATCH_IRE_ILL_GROUP | MATCH_IRE_SECATTR;
 			io->ipsec_out_ill_index =
 			    ipif->ipif_ill->ill_phyint->phyint_ifindex;
 		}
@@ -18791,7 +19433,7 @@
 		ire = NULL;
 		if (xmit_ill == NULL) {
 			ire = ire_ctable_lookup(dst, 0, 0, ipif,
-			    zoneid, match_flags);
+			    zoneid, MBLK_GETLABEL(mp), match_flags);
 		}
 
 		/*
@@ -18860,7 +19502,7 @@
 			}
 		}
 	} else {
-		ire = ire_cache_lookup(dst, zoneid);
+		ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp));
 		if ((ire != NULL) && (ire->ire_type &
 		    (IRE_BROADCAST | IRE_LOCAL | IRE_LOOPBACK))) {
 			ignore_dontroute = B_TRUE;
@@ -18939,7 +19581,7 @@
 		if (attach_ill != NULL) {
 			ipif_t	*attach_ipif;
 
-			match_flags = MATCH_IRE_ILL;
+			match_flags = MATCH_IRE_ILL | MATCH_IRE_SECATTR;
 
 			/*
 			 * Check if we need an ire that will not be
@@ -18955,7 +19597,7 @@
 				goto drop_pkt;
 			}
 			ire = ire_ctable_lookup(dst, 0, 0, attach_ipif,
-			    zoneid, match_flags);
+			    zoneid, MBLK_GETLABEL(mp), match_flags);
 			ipif_refrele(attach_ipif);
 		} else if (xmit_ill != NULL || (connp != NULL &&
 			    connp->conn_xmit_if_ill != NULL)) {
@@ -19016,9 +19658,9 @@
 			match_flags = MATCH_IRE_MARK_PRIVATE_ADDR |
 			    MATCH_IRE_GW;
 			ire = ire_ctable_lookup(dst, nexthop_addr, 0,
-			    NULL, zoneid, match_flags);
-		} else {
-			ire = ire_cache_lookup(dst, zoneid);
+			    NULL, zoneid, MBLK_GETLABEL(mp), match_flags);
+		} else {
+			ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp));
 		}
 		if (!ire) {
 			/*
@@ -19121,7 +19763,8 @@
 		 * of the current message. It will be used
 		 * to initiate additional route resolutions.
 		 */
-		multirt_need_resolve = ire_multirt_need_resolve(ire->ire_addr);
+		multirt_need_resolve = ire_multirt_need_resolve(ire->ire_addr,
+		    MBLK_GETLABEL(first_mp));
 		ip2dbg(("ip_wput[noirefound]: ire %p, "
 		    "multirt_need_resolve %d, first_mp %p\n",
 		    (void *)ire, multirt_need_resolve, (void *)first_mp));
@@ -19166,6 +19809,16 @@
 		CONN_DEC_REF(connp);
 	return;
 
+icmp_parameter_problem:
+	/* could not have originated externally */
+	ASSERT(mp->b_prev == NULL);
+	if (ip_hdr_complete(ipha, zoneid) == 0) {
+		BUMP_MIB(&ip_mib, ipOutNoRoutes);
+		/* it's the IP header length that's in trouble */
+		icmp_param_problem(q, first_mp, 0);
+		first_mp = NULL;
+	}
+
 drop_pkt:
 	ip1dbg(("ip_wput: dropped packet\n"));
 	if (ire != NULL)
@@ -19808,7 +20461,8 @@
 		}
 	}
 
-	if (ire->ire_type == IRE_LOCAL && ire->ire_zoneid != zoneid) {
+	if (ire->ire_type == IRE_LOCAL && ire->ire_zoneid != zoneid &&
+	    ire->ire_zoneid != ALL_ZONES) {
 		/*
 		 * When a zone sends a packet to another zone, we try to deliver
 		 * the packet under the same conditions as if the destination
@@ -19818,7 +20472,7 @@
 		 * ip_newroute() does.
 		 */
 		ire_t *src_ire = ire_ftable_lookup(ipha->ipha_dst, 0, 0, 0,
-		    NULL, NULL, zoneid, 0, (MATCH_IRE_RECURSIVE |
+		    NULL, NULL, zoneid, 0, NULL, (MATCH_IRE_RECURSIVE |
 		    MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE));
 		if (src_ire != NULL &&
 		    !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))) {
@@ -19980,7 +20634,7 @@
 		if (ire->ire_type == IRE_BROADCAST &&
 		    ire->ire_zoneid != zoneid) {
 			ire_t *src_ire = ire_ctable_lookup(dst, 0,
-			    IRE_BROADCAST, ire->ire_ipif, zoneid,
+			    IRE_BROADCAST, ire->ire_ipif, zoneid, NULL,
 			    (MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP));
 			if (src_ire != NULL) {
 				src = src_ire->ire_src_addr;
@@ -20786,7 +21440,6 @@
 					}
 				}
 
-			noprepend:
 				ASSERT(ipsec_len == 0);
 				mp1 = ip_wput_attach_llhdr(mp, ire,
 				    IPP_LOCAL_OUT, ill_index);
@@ -21619,6 +22272,8 @@
 		    "couldn't copy hdr");
 		return;
 	}
+	if (DB_CRED(mp) != NULL)
+		mblk_setcred(hdr_mp, DB_CRED(mp));
 
 	/* Store the starting offset, with the MoreFrags flag. */
 	i1 = offset | IPH_MF | frag_flag;
@@ -21824,6 +22479,8 @@
 			return;
 		} else {
 			xmit_mp->b_cont = mp;
+			if (DB_CRED(mp) != NULL)
+				mblk_setcred(xmit_mp, DB_CRED(mp));
 			/* Get priority marking, if any. */
 			if (DB_TYPE(xmit_mp) == M_DATA)
 				xmit_mp->b_band = mp->b_band;
@@ -22073,6 +22730,8 @@
 				xmit_mp = mp;
 			} else if ((xmit_mp = copyb(ll_hdr_mp)) != NULL) {
 				xmit_mp->b_cont = mp;
+				if (DB_CRED(mp) != NULL)
+					mblk_setcred(xmit_mp, DB_CRED(mp));
 				/* Get priority marking, if any. */
 				if (DB_TYPE(xmit_mp) == M_DATA)
 					xmit_mp->b_band = mp->b_band;
@@ -22428,6 +23087,7 @@
 		if ((ushort_t)ire_type == IRE_BROADCAST) {
 			freemsg(first_mp);
 			BUMP_MIB(&ip_mib, ipInDiscards);
+			ip2dbg(("ip_wput_local: discard broadcast\n"));
 			return;
 		}
 
@@ -22560,7 +23220,7 @@
 				off = opt[IPOPT_OFFSET] - 1;
 				bcopy((char *)opt + off, &dst, IP_ADDR_LEN);
 				ire = ire_ctable_lookup(dst, 0, IRE_LOCAL,
-				    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+				    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 				if (ire == NULL) {
 					/* Not for us */
 					break;
@@ -22656,7 +23316,8 @@
 	 * ipsec_out_attach_if so that this will not be load spread in
 	 * ip_newroute_ipif.
 	 */
-	ire = ire_ctable_lookup(dst, 0, 0, ipif, ALL_ZONES, MATCH_IRE_ILL);
+	ire = ire_ctable_lookup(dst, 0, 0, ipif, ALL_ZONES, NULL,
+	    MATCH_IRE_ILL);
 	if (!ire) {
 		/*
 		 * Mark this packet to make it be delivered to
@@ -22751,6 +23412,15 @@
 			mp1->b_band = mp->b_band;
 			mp1->b_cont = mp;
 			/*
+			 * certain system generated traffic may not
+			 * have cred/label in ip header block. This
+			 * is true even for a labeled system. But for
+			 * labeled traffic, inherit the label in the
+			 * new header.
+			 */
+			if (DB_CRED(mp) != NULL)
+				mblk_setcred(mp1, DB_CRED(mp));
+			/*
 			 * XXX disable ICK_VALID and compute checksum
 			 * here; can happen if ire_fp_mp changes and
 			 * it can't be copied now due to insufficient
@@ -22770,6 +23440,15 @@
 		}
 		UNLOCK_IRE_FP_MP(ire);
 		mp1->b_cont = mp;
+		/*
+		 * certain system generated traffic may not
+		 * have cred/label in ip header block. This
+		 * is true even for a labeled system. But for
+		 * labeled traffic, inherit the label in the
+		 * new header.
+		 */
+		if (DB_CRED(mp) != NULL)
+			mblk_setcred(mp1, DB_CRED(mp));
 		if (!qos_done && (proc != 0) && IPP_ENABLED(proc)) {
 			ip_process(proc, &mp1, ill_index);
 			if (mp1 == NULL)
@@ -22812,7 +23491,7 @@
 	hwaccel = io->ipsec_out_accelerated;
 	zoneid = io->ipsec_out_zoneid;
 	ASSERT(zoneid != ALL_ZONES);
-	match_flags = MATCH_IRE_ILL_GROUP;
+	match_flags = MATCH_IRE_ILL_GROUP | MATCH_IRE_SECATTR;
 	/* Multicast addresses should have non-zero ill_index. */
 	v6dstp = &ip6h->ip6_dst;
 	ASSERT(ip6h->ip6_nxt != IPPROTO_RAW);
@@ -22867,7 +23546,7 @@
 			ire = ire_arg;
 		} else {
 			ire = ire_ctable_lookup_v6(v6dstp, 0, 0, ipif,
-			    zoneid, match_flags);
+			    zoneid, MBLK_GETLABEL(mp), match_flags);
 			ire_need_rele = B_TRUE;
 		}
 		if (ire != NULL) {
@@ -22909,14 +23588,14 @@
 				return;
 			}
 			ire = ire_ctable_lookup_v6(v6dstp, 0, 0, ipif,
-			    zoneid, match_flags);
+			    zoneid, MBLK_GETLABEL(mp), match_flags);
 			ire_need_rele = B_TRUE;
 			ipif_refrele(ipif);
 		} else {
 			if (ire_arg != NULL) {
 				ire = ire_arg;
 			} else {
-				ire = ire_cache_lookup_v6(v6dstp, zoneid);
+				ire = ire_cache_lookup_v6(v6dstp, zoneid, NULL);
 				ire_need_rele = B_TRUE;
 			}
 		}
@@ -23103,7 +23782,7 @@
 	attach_if = io->ipsec_out_attach_if;
 	zoneid = io->ipsec_out_zoneid;
 	ASSERT(zoneid != ALL_ZONES);
-	match_flags = MATCH_IRE_ILL_GROUP;
+	match_flags = MATCH_IRE_ILL_GROUP | MATCH_IRE_SECATTR;
 	if (ill_index != 0) {
 		if (ill == NULL) {
 			ill = ip_grab_attach_ill(NULL, ipsec_mp,
@@ -23120,7 +23799,7 @@
 		 * honor it.
 		 */
 		if (attach_if) {
-			match_flags = MATCH_IRE_ILL;
+			match_flags = MATCH_IRE_ILL | MATCH_IRE_SECATTR;
 
 			/*
 			 * Check if we need an ire that will not be
@@ -23154,7 +23833,8 @@
 		 * value of the ipif in ip_wput. All we need now is
 		 * an ire to send this downstream.
 		 */
-		ire = ire_ctable_lookup(dst, 0, 0, ipif, zoneid, match_flags);
+		ire = ire_ctable_lookup(dst, 0, 0, ipif, zoneid,
+		    MBLK_GETLABEL(mp), match_flags);
 		if (ire != NULL) {
 			ill_t *ill1;
 			/*
@@ -23199,13 +23879,14 @@
 	} else {
 		if (attach_if) {
 			ire = ire_ctable_lookup(dst, 0, 0, ill->ill_ipif,
-			    zoneid, match_flags);
+			    zoneid, MBLK_GETLABEL(mp), match_flags);
 		} else {
 			if (ire_arg != NULL) {
 				ire = ire_arg;
 				ire_need_rele = B_FALSE;
 			} else {
-				ire = ire_cache_lookup(dst, zoneid);
+				ire = ire_cache_lookup(dst, zoneid,
+				    MBLK_GETLABEL(mp));
 			}
 		}
 		if (ire != NULL) {
@@ -24497,6 +25178,21 @@
 		ip_ire_req(q, mp);
 		return;
 	case M_CTL:
+		if (mp->b_wptr - mp->b_rptr < sizeof (uint32_t))
+			break;
+
+		if (connp != NULL && *(uint32_t *)mp->b_rptr ==
+		    IP_ULP_OUT_LABELED) {
+			out_labeled_t *olp;
+
+			if (mp->b_wptr - mp->b_rptr != sizeof (*olp))
+				break;
+			olp = (out_labeled_t *)mp->b_rptr;
+			connp->conn_ulp_labeled = olp->out_qnext == q;
+			freemsg(mp);
+			return;
+		}
+
 		/* M_CTL messages are used by ARP to tell us things. */
 		if ((mp->b_wptr - mp->b_rptr) < sizeof (arc_t))
 			break;
@@ -24921,7 +25617,8 @@
 			if (optval == IPOPT_SSRR) {
 				ire = ire_ftable_lookup(dst, 0, 0,
 				    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0,
-				    MATCH_IRE_TYPE);
+				    MBLK_GETLABEL(mp),
+				    MATCH_IRE_TYPE | MATCH_IRE_SECATTR);
 				if (ire == NULL) {
 					ip1dbg(("ip_wput_options: SSRR not"
 					    " directly reachable: 0x%x\n",
@@ -25557,7 +26254,8 @@
 		if (ipif == NULL)
 			return (B_FALSE);
 		ire = ire_ctable_lookup(dst, 0, IRE_BROADCAST, ipif,
-		    connp->conn_zoneid, (MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP));
+		    connp->conn_zoneid, NULL,
+		    (MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP));
 		ipif_refrele(ipif);
 		if (ire != NULL) {
 			ire_refrele(ire);
@@ -25812,7 +26510,7 @@
 			continue;
 
 		ire_gw = ire_ftable_lookup(ire->ire_gateway_addr, 0, 0,
-		    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0,
+		    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0, NULL,
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE);
 		/* No resolver exists for the gateway; skip this ire. */
 		if (ire_gw == NULL)
@@ -26303,7 +27001,7 @@
 	}
 	ip6h = (isv4) ? NULL : (ip6_t *)ipha;
 
-	connp = ipcl_classify_raw(IPPROTO_SCTP, zoneid, ports, ipha);
+	connp = ipcl_classify_raw(mp, IPPROTO_SCTP, zoneid, ports, ipha);
 	if (connp == NULL) {
 		sctp_ootb_input(first_mp, recv_ill, ipif_seqid, zoneid,
 		    mctl_present);
@@ -26400,7 +27098,7 @@
 		goto dont_forward;
 
 	src_ire = ire_ctable_lookup(ipha->ipha_src, 0, IRE_BROADCAST, NULL,
-	    ALL_ZONES, MATCH_IRE_TYPE);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	if (src_ire != NULL) {
 		ire_refrele(src_ire);
 		goto dont_forward;
@@ -26449,3 +27147,100 @@
 	}
 	return (B_FALSE);
 }
+
+/*
+ * Return B_TRUE if the buffers differ in length or content.
+ * This is used for comparing extension header buffers.
+ * Note that an extension header would be declared different
+ * even if all that changed was the next header value in that header i.e.
+ * what really changed is the next extension header.
+ */
+boolean_t
+ip_cmpbuf(const void *abuf, uint_t alen, boolean_t b_valid, const void *bbuf,
+    uint_t blen)
+{
+	if (!b_valid)
+		blen = 0;
+
+	if (alen != blen)
+		return (B_TRUE);
+	if (alen == 0)
+		return (B_FALSE);	/* Both zero length */
+	return (bcmp(abuf, bbuf, alen));
+}
+
+/*
+ * Preallocate memory for ip_savebuf(). Returns B_TRUE if ok.
+ * Return B_FALSE if memory allocation fails - don't change any state!
+ */
+boolean_t
+ip_allocbuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
+    const void *src, uint_t srclen)
+{
+	void *dst;
+
+	if (!src_valid)
+		srclen = 0;
+
+	ASSERT(*dstlenp == 0);
+	if (src != NULL && srclen != 0) {
+		dst = mi_alloc(srclen, BPRI_MED);
+		if (dst == NULL)
+			return (B_FALSE);
+	} else {
+		dst = NULL;
+	}
+	if (*dstp != NULL)
+		mi_free(*dstp);
+	*dstp = dst;
+	*dstlenp = dst == NULL ? 0 : srclen;
+	return (B_TRUE);
+}
+
+/*
+ * Replace what is in *dst, *dstlen with the source.
+ * Assumes ip_allocbuf has already been called.
+ */
+void
+ip_savebuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
+    const void *src, uint_t srclen)
+{
+	if (!src_valid)
+		srclen = 0;
+
+	ASSERT(*dstlenp == srclen);
+	if (src != NULL && srclen != 0)
+		bcopy(src, *dstp, srclen);
+}
+
+/*
+ * Free the storage pointed to by the members of an ip6_pkt_t.
+ */
+void
+ip6_pkt_free(ip6_pkt_t *ipp)
+{
+	ASSERT(ipp->ipp_pathmtu == NULL && !(ipp->ipp_fields & IPPF_PATHMTU));
+
+	if (ipp->ipp_fields & IPPF_HOPOPTS) {
+		kmem_free(ipp->ipp_hopopts, ipp->ipp_hopoptslen);
+		ipp->ipp_hopopts = NULL;
+		ipp->ipp_hopoptslen = 0;
+	}
+	if (ipp->ipp_fields & IPPF_RTDSTOPTS) {
+		kmem_free(ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen);
+		ipp->ipp_rtdstopts = NULL;
+		ipp->ipp_rtdstoptslen = 0;
+	}
+	if (ipp->ipp_fields & IPPF_DSTOPTS) {
+		kmem_free(ipp->ipp_dstopts, ipp->ipp_dstoptslen);
+		ipp->ipp_dstopts = NULL;
+		ipp->ipp_dstoptslen = 0;
+	}
+	if (ipp->ipp_fields & IPPF_RTHDR) {
+		kmem_free(ipp->ipp_rthdr, ipp->ipp_rthdrlen);
+		ipp->ipp_rthdr = NULL;
+		ipp->ipp_rthdrlen = 0;
+	}
+	ipp->ipp_fields &= ~(IPPF_HOPOPTS | IPPF_RTDSTOPTS | IPPF_DSTOPTS |
+	    IPPF_RTHDR);
+}
--- a/usr/src/uts/common/inet/ip/ip6.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip6.c	Fri Mar 24 12:29:20 2006 -0800
@@ -38,7 +38,6 @@
 #include <sys/strsubr.h>
 #define	_SUN_TPI_VERSION	2
 #include <sys/tihdr.h>
-#include <sys/tiuser.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/cmn_err.h>
@@ -56,7 +55,6 @@
 #include <sys/iphada.h>
 #include <sys/policy.h>
 #include <net/if.h>
-#include <net/if_arp.h>
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/if_dl.h>
@@ -71,7 +69,6 @@
 #include <inet/mib2.h>
 #include <inet/nd.h>
 #include <inet/arp.h>
-#include <inet/snmpcom.h>
 
 #include <inet/ip.h>
 #include <inet/ip_impl.h>
@@ -94,13 +91,17 @@
 #include <inet/ipsec_impl.h>
 #include <inet/tun.h>
 #include <inet/sctp_ip.h>
-#include <sys/multidata.h>
 #include <sys/pattr.h>
 #include <inet/ipclassifier.h>
 #include <inet/ipsecah.h>
 #include <inet/udp_impl.h>
 #include <sys/squeue.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+
+#include <rpc/pmap_prot.h>
+
 extern squeue_func_t ip_input_proc;
 
 /*
@@ -179,6 +180,14 @@
 mib2_ipv6IfStatsEntry_t	ip6_mib;
 mib2_ipv6IfIcmpEntry_t	icmp6_mib;
 
+/*
+ * ip6opt_ls is used to enable IPv6 (via /etc/system on TX systems).
+ * We need to do this because we didn't obtain the IP6OPT_LS (0x0a)
+ * from IANA. This mechanism will remain in effect until an official
+ * number is obtained.
+ */
+uchar_t ip6opt_ls;
+
 uint_t ipv6_ire_default_count;	/* Number of IPv6 IRE_DEFAULT entries */
 uint_t ipv6_ire_default_index;	/* Walking IPv6 index used to mod in */
 
@@ -358,6 +367,22 @@
 			return;
 	}
 
+	/*
+	 * On a labeled system, we have to check whether the zone itself is
+	 * permitted to receive raw traffic.
+	 */
+	if (is_system_labeled()) {
+		if (zoneid == ALL_ZONES)
+			zoneid = tsol_packet_to_zoneid(mp);
+		if (!tsol_can_accept_raw(mp, B_FALSE)) {
+			ip1dbg(("icmp_inbound_v6: zone %d can't receive raw",
+			    zoneid));
+			BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors);
+			freemsg(first_mp);
+			return;
+		}
+	}
+
 	icmp6 = (icmp6_t *)(&mp->b_rptr[hdr_length]);
 	ip2dbg(("icmp_inbound_v6: type %d code %d\n", icmp6->icmp6_type,
 	    icmp6->icmp6_code));
@@ -507,7 +532,8 @@
 			 * we do this, we will try to forward all packets
 			 * meant to our LOCAL address.
 			 */
-			ire = ire_cache_lookup_v6(&ip6h->ip6_dst, ALL_ZONES);
+			ire = ire_cache_lookup_v6(&ip6h->ip6_dst, ALL_ZONES,
+			    NULL);
 			if (ire == NULL || ire->ire_type != IRE_LOCAL) {
 				mp = ip_add_info_v6(mp, NULL, &ip6h->ip6_dst);
 				if (mp == NULL) {
@@ -552,6 +578,7 @@
 			first_mp->b_cont = mp;
 		}
 		ii->ipsec_in_zoneid = zoneid;
+		ASSERT(zoneid != ALL_ZONES);
 		if (!ipsec_in_to_out(first_mp, NULL, ip6h)) {
 			BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards);
 			return;
@@ -708,8 +735,8 @@
 
 	if (IN6_IS_ADDR_LINKLOCAL(&inner_ip6h->ip6_dst)) {
 		first_ire = ire_ctable_lookup_v6(&inner_ip6h->ip6_dst, NULL,
-			IRE_CACHE, ill->ill_ipif, ALL_ZONES,
-			MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP);
+		    IRE_CACHE, ill->ill_ipif, ALL_ZONES, NULL,
+		    MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP);
 
 		if (first_ire == NULL) {
 			if (ip_debug > 2) {
@@ -764,7 +791,7 @@
 		 * for non-link local destinations we match only on the IRE type
 		 */
 		ire = ire_ctable_lookup_v6(&inner_ip6h->ip6_dst, NULL,
-		    IRE_CACHE, ill->ill_ipif, ALL_ZONES, MATCH_IRE_TYPE);
+		    IRE_CACHE, ill->ill_ipif, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 		if (ire == NULL) {
 			if (ip_debug > 2) {
 				/* ip1dbg */
@@ -1224,7 +1251,7 @@
 	 * router goes away between now and then.
 	 */
 	ire = ire_route_lookup_v6(&rd->nd_rd_dst, 0,
-	    &ip6h->ip6_src, 0, ill->ill_ipif, NULL, ALL_ZONES,
+	    &ip6h->ip6_src, 0, ill->ill_ipif, NULL, ALL_ZONES, NULL,
 	    MATCH_IRE_GW | MATCH_IRE_ILL_GROUP);
 	if (ire == NULL)
 		return (B_FALSE);
@@ -1288,7 +1315,7 @@
 		return;
 	}
 	prev_ire = ire_route_lookup_v6(dst, 0, src, 0, ipif, NULL,
-	    ALL_ZONES, MATCH_IRE_GW | MATCH_IRE_ILL_GROUP);
+	    ALL_ZONES, NULL, MATCH_IRE_GW | MATCH_IRE_ILL_GROUP);
 	ipif_refrele(ipif);
 	/*
 	 * Check that
@@ -1331,7 +1358,7 @@
 		ire_t *sire;
 
 		tmp_ire = ire_ftable_lookup_v6(dst, 0, gateway, 0, NULL, &sire,
-		    ALL_ZONES, 0,
+		    ALL_ZONES, 0, NULL,
 		    (MATCH_IRE_RECURSIVE | MATCH_IRE_GW | MATCH_IRE_DEFAULT));
 		if (sire != NULL) {
 			bcopy(&sire->ire_uinfo, &ulp_info, sizeof (iulp_t));
@@ -1400,7 +1427,9 @@
 		    0,
 		    0,
 		    (RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST),
-		    &ulp_info);
+		    &ulp_info,
+		    NULL,
+		    NULL);
 	} else {
 		/*
 		 * Just create an on link entry, may or may not be a router
@@ -1423,7 +1452,9 @@
 		    0,
 		    0,
 		    0,
-		    &ulp_info);
+		    &ulp_info,
+		    NULL,
+		    NULL);
 	}
 	if (ire == NULL)
 		goto fail_redirect;
@@ -1450,7 +1481,7 @@
 		 * modifying an existing redirect.
 		 */
 		redir_ire = ire_ftable_lookup_v6(dst, 0, src, IRE_HOST_REDIRECT,
-		    ire->ire_ipif, NULL, ALL_ZONES, 0,
+		    ire->ire_ipif, NULL, ALL_ZONES, 0, NULL,
 		    (MATCH_IRE_GW | MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP));
 
 		ire_refrele(ire);		/* Held in ire_add_v6 */
@@ -1521,7 +1552,7 @@
 	}
 
 	ire = ire_route_lookup_v6(origdst, 0, 0, (IRE_LOCAL|IRE_LOOPBACK),
-	    NULL, NULL, zoneid, (MATCH_IRE_TYPE|MATCH_IRE_ZONEONLY));
+	    NULL, NULL, zoneid, NULL, (MATCH_IRE_TYPE|MATCH_IRE_ZONEONLY));
 	if (ire != NULL) {
 		/* Destined to one of our addresses */
 		*src = *origdst;
@@ -1535,7 +1566,7 @@
 	if (ill == NULL) {
 		/* What is the route back to the original source? */
 		ire = ire_route_lookup_v6(origsrc, 0, 0, 0,
-		    NULL, NULL, zoneid,
+		    NULL, NULL, zoneid, NULL,
 		    (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE));
 		if (ire == NULL) {
 			BUMP_MIB(&ip6_mib, ipv6OutNoRoutes);
@@ -1561,7 +1592,8 @@
 	 * original source. Use what in the route to the source.
 	 */
 	ire = ire_route_lookup_v6(origsrc, 0, 0, 0,
-	    NULL, NULL, zoneid, (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE));
+	    NULL, NULL, zoneid, NULL,
+	    (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE));
 	if (ire == NULL) {
 		BUMP_MIB(&ip6_mib, ipv6OutNoRoutes);
 		return (NULL);
@@ -2176,6 +2208,20 @@
 			goto bad_addr;
 		}
 
+		/*
+		 *
+		 * The udp module never sends down a zero-length address,
+		 * and allowing this on a labeled system will break MLP
+		 * functionality.
+		 */
+		if (is_system_labeled() && protocol == IPPROTO_UDP)
+			goto bad_addr;
+
+		/* Allow ipsec plumbing */
+		if (connp->conn_mac_exempt && protocol != IPPROTO_AH &&
+		    protocol != IPPROTO_ESP)
+			goto bad_addr;
+
 		connp->conn_srcv6 = ipv6_all_zeros;
 		ipcl_proto_insert_v6(connp, protocol);
 
@@ -2420,7 +2466,7 @@
 
 	if (!IN6_IS_ADDR_UNSPECIFIED(v6src)) {
 		src_ire = ire_route_lookup_v6(v6src, 0, 0,
-		    0, NULL, NULL, zoneid, MATCH_IRE_ZONEONLY);
+		    0, NULL, NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
 		/*
 		 * If an address other than in6addr_any is requested,
 		 * we verify that it is a valid address for bind
@@ -2428,7 +2474,6 @@
 		 * readability compared to a condition check.
 		 */
 		ASSERT(src_ire == NULL || !(src_ire->ire_type & IRE_BROADCAST));
-		/* LINTED - statement has no consequent */
 		if (IRE_IS_LOCAL(src_ire)) {
 			/*
 			 * (2) Bind to address of local UP interface
@@ -2463,10 +2508,8 @@
 			mutex_exit(&connp->conn_lock);
 			save_ire = src_ire;
 			src_ire = NULL;
-			if (multi_ipif == NULL ||
-			    !ire_requested || (src_ire =
-			    ipif_to_ire_v6(multi_ipif)) ==
-			    NULL) {
+			if (multi_ipif == NULL || !ire_requested ||
+			    (src_ire = ipif_to_ire_v6(multi_ipif)) == NULL) {
 				src_ire = save_ire;
 				error = EADDRNOTAVAIL;
 			} else {
@@ -2545,6 +2588,15 @@
 		}
 	}
 bad_addr:
+	if (error != 0) {
+		if (connp->conn_anon_port) {
+			(void) tsol_mlp_anon(crgetzone(connp->conn_cred),
+			    connp->conn_mlp_type, connp->conn_ulp, ntohs(lport),
+			    B_FALSE);
+		}
+		connp->conn_mlp_type = mlptSingle;
+	}
+
 	if (src_ire != NULL)
 		ire_refrele(src_ire);
 
@@ -2683,9 +2735,9 @@
 			ipif_refrele(ipif);
 	} else {
 		dst_ire = ire_route_lookup_v6(v6dst, NULL, NULL, 0,
-		    NULL, &sire, zoneid,
+		    NULL, &sire, zoneid, MBLK_GETLABEL(mp),
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-		    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE);
+		    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE | MATCH_IRE_SECATTR);
 		/*
 		 * We also prevent ire's with src address INADDR_ANY to
 		 * be used, which are created temporarily for
@@ -2722,6 +2774,33 @@
 	}
 
 	/*
+	 * We now know that routing will allow us to reach the destination.
+	 * Check whether Trusted Solaris policy allows communication with this
+	 * host, and pretend that the destination is unreachable if not.
+	 *
+	 * This is never a problem for TCP, since that transport is known to
+	 * compute the label properly as part of the tcp_rput_other T_BIND_ACK
+	 * handling.  If the remote is unreachable, it will be detected at that
+	 * point, so there's no reason to check it here.
+	 *
+	 * Note that for sendto (and other datagram-oriented friends), this
+	 * check is done as part of the data path label computation instead.
+	 * The check here is just to make non-TCP connect() report the right
+	 * error.
+	 */
+	if (dst_ire != NULL && is_system_labeled() &&
+	    !IPCL_IS_TCP(connp) &&
+	    tsol_compute_label_v6(DB_CREDDEF(mp, connp->conn_cred), v6dst, NULL,
+	    connp->conn_mac_exempt) != 0) {
+		error = EHOSTUNREACH;
+		if (ip_debug > 2) {
+			pr_addr_dbg("ip_bind_connected: no label for dst %s\n",
+			    AF_INET6, v6dst);
+		}
+		goto bad_addr;
+	}
+
+	/*
 	 * If the app does a connect(), it means that it will most likely
 	 * send more than 1 packet to the destination.  It makes sense
 	 * to clear the temporary flag.
@@ -2760,9 +2839,10 @@
 
 	if (dst_ire != NULL &&
 	    dst_ire->ire_type == IRE_LOCAL &&
-	    dst_ire->ire_zoneid != zoneid) {
+	    dst_ire->ire_zoneid != zoneid &&
+	    dst_ire->ire_zoneid != ALL_ZONES) {
 		src_ire = ire_ftable_lookup_v6(v6dst, 0, 0, 0, NULL, NULL,
-		    zoneid, 0,
+		    zoneid, 0, NULL,
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
 		    MATCH_IRE_RJ_BHOLE);
 		if (src_ire == NULL) {
@@ -2790,7 +2870,8 @@
 			sire = NULL;
 		} else if (dst_ire->ire_type == IRE_CACHE &&
 		    (dst_ire->ire_flags & RTF_SETSRC)) {
-			ASSERT(dst_ire->ire_zoneid == zoneid);
+			ASSERT(dst_ire->ire_zoneid == zoneid ||
+			    dst_ire->ire_zoneid == ALL_ZONES);
 			*v6src = dst_ire->ire_src_addr_v6;
 		} else {
 			/*
@@ -2866,7 +2947,7 @@
 	 * UP interface for hard binding.
 	 */
 	src_ire = ire_route_lookup_v6(v6src, 0, 0, 0, NULL,
-	    NULL, zoneid, MATCH_IRE_ZONEONLY);
+	    NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
 
 	/* src_ire must be a local|loopback */
 	if (!IRE_IS_LOCAL(src_ire)) {
@@ -3130,7 +3211,7 @@
 	in6_addr_t src = ip6h->ip6_src;
 	boolean_t one_only;
 	mblk_t *first_mp = mp;
-	boolean_t secure;
+	boolean_t secure, shared_addr;
 	conn_t	*connp, *first_connp, *next_connp;
 	connf_t *connfp;
 
@@ -3149,13 +3230,25 @@
 	one_only = ((nexthdr == IPPROTO_ENCAP || nexthdr == IPPROTO_IPV6) &&
 	    !IN6_IS_ADDR_MULTICAST(&dst));
 
+	shared_addr = (zoneid == ALL_ZONES);
+	if (shared_addr) {
+		/*
+		 * We don't allow multilevel ports for raw IP, so no need to
+		 * check for that here.
+		 */
+		zoneid = tsol_packet_to_zoneid(mp);
+	}
+
 	connfp = &ipcl_proto_fanout_v6[nexthdr];
 	mutex_enter(&connfp->connf_lock);
 	connp = connfp->connf_head;
 	for (connp = connfp->connf_head; connp != NULL;
 		connp = connp->conn_next) {
 		if (IPCL_PROTO_MATCH_V6(connp, nexthdr, ip6h, ill, flags,
-		    zoneid))
+		    zoneid) &&
+		    (!is_system_labeled() ||
+		    tsol_receive_local(mp, &dst, IPV6_VERSION, shared_addr,
+		    connp)))
 			break;
 	}
 
@@ -3195,7 +3288,10 @@
 	for (;;) {
 		while (connp != NULL) {
 			if (IPCL_PROTO_MATCH_V6(connp, nexthdr, ip6h, ill,
-			    flags, zoneid))
+			    flags, zoneid) &&
+			    (!is_system_labeled() ||
+			    tsol_receive_local(mp, &dst, IPV6_VERSION,
+			    shared_addr, connp)))
 				break;
 			connp = connp->conn_next;
 		}
@@ -3630,6 +3726,7 @@
 	conn_t 		*next_conn;
 	mblk_t		*mp1, *first_mp1;
 	in6_addr_t	src;
+	boolean_t	shared_addr;
 
 	first_mp = mp;
 	if (mctl_present) {
@@ -3646,6 +3743,20 @@
 	dst = ip6h->ip6_dst;
 	src = ip6h->ip6_src;
 
+	shared_addr = (zoneid == ALL_ZONES);
+	if (shared_addr) {
+		zoneid = tsol_mlp_findzone(IPPROTO_UDP, dstport);
+		/*
+		 * If no shared MLP is found, tsol_mlp_findzone returns
+		 * ALL_ZONES.  In that case, we assume it's SLP, and
+		 * search for the zone based on the packet label.
+		 * That will also return ALL_ZONES on failure, but
+		 * we never allow conn_zoneid to be set to ALL_ZONES.
+		 */
+		if (zoneid == ALL_ZONES)
+			zoneid = tsol_packet_to_zoneid(mp);
+	}
+
 	/* Attempt to find a client stream based on destination port. */
 	connfp = &ipcl_udp_fanout[IPCL_UDP_HASH(dstport)];
 	mutex_enter(&connfp->connf_lock);
@@ -3666,13 +3777,17 @@
 		if (connp == NULL || connp->conn_upq == NULL)
 			goto notfound;
 
+		if (is_system_labeled() &&
+		    !tsol_receive_local(mp, &dst, IPV6_VERSION, shared_addr,
+		    connp))
+			goto notfound;
+
 		/* Found a client */
 		CONN_INC_REF(connp);
 		mutex_exit(&connfp->connf_lock);
 
 		if (CONN_UDP_FLOWCTLD(connp)) {
 			freemsg(first_mp);
-			BUMP_MIB(ill->ill_ip6_mib, udpInOverflows);
 			CONN_DEC_REF(connp);
 			return;
 		}
@@ -3733,15 +3848,12 @@
 		return;
 	}
 
-	/*
-	 * The code is fine but we shouldn't be walking the conn_next
-	 * list in IPv6 (its a classifier private data struct). Maybe create
-	 * a classifier API to put a REF_HOLD on all matching conn in the
-	 * list and return an array.
-	 */
 	while (connp != NULL) {
 		if ((IPCL_UDP_MATCH_V6(connp, dstport, dst, srcport, src)) &&
-		    conn_wantpacket_v6(connp, ill, ip6h, flags, zoneid))
+		    conn_wantpacket_v6(connp, ill, ip6h, flags, zoneid) &&
+		    (!is_system_labeled() ||
+		    tsol_receive_local(mp, &dst, IPV6_VERSION, shared_addr,
+		    connp)))
 			break;
 		connp = connp->conn_next;
 	}
@@ -3757,7 +3869,10 @@
 		while (connp != NULL) {
 			if (IPCL_UDP_MATCH_V6(connp, dstport, dst, srcport,
 			    src) && conn_wantpacket_v6(connp, ill, ip6h,
-			    flags, zoneid))
+			    flags, zoneid) &&
+			    (!is_system_labeled() ||
+			    tsol_receive_local(mp, &dst, IPV6_VERSION,
+			    shared_addr, connp)))
 				break;
 			connp = connp->conn_next;
 		}
@@ -3791,13 +3906,20 @@
 			/* Add header */
 			mp1 = ip_add_info_v6(mp1, inill, &dst);
 		}
+		/* mp1 could have changed */
+		if (mctl_present)
+			first_mp1->b_cont = mp1;
+		else
+			first_mp1 = mp1;
 		if (mp1 == NULL) {
+			if (mctl_present)
+				freeb(first_mp1);
 			BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards);
 			goto next_one;
 		}
 		if (CONN_UDP_FLOWCTLD(connp)) {
 			BUMP_MIB(ill->ill_ip6_mib, udpInOverflows);
-			freemsg(mp1);
+			freemsg(first_mp1);
 			goto next_one;
 		}
 
@@ -4261,6 +4383,9 @@
 	boolean_t	need_rele = B_FALSE;
 	boolean_t	do_attach_ill = B_FALSE;
 	boolean_t	ip6_asp_table_held = B_FALSE;
+	tsol_ire_gw_secattr_t *attrp = NULL;
+	tsol_gcgrp_t	*gcgrp = NULL;
+	tsol_gcgrp_addr_t ga;
 
 	ASSERT(!IN6_IS_ADDR_MULTICAST(v6dstp));
 
@@ -4329,9 +4454,10 @@
 
 	if (ill == NULL) {
 		match_flags = MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-		    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE;
+		    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE | MATCH_IRE_SECATTR;
 		ire = ire_ftable_lookup_v6(v6dstp, 0, 0, 0,
-		    NULL, &sire, zoneid, 0, match_flags);
+		    NULL, &sire, zoneid, 0, MBLK_GETLABEL(mp),
+		    match_flags);
 		/*
 		 * ire_add_then_send -> ip_newroute_v6 in the CGTP case passes
 		 * in a NULL ill, but the packet could be a neighbor
@@ -4355,9 +4481,9 @@
 			match_flags = MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
 			    MATCH_IRE_RJ_BHOLE | MATCH_IRE_ILL_GROUP;
 		}
-		match_flags |= MATCH_IRE_PARENT;
-		ire = ire_ftable_lookup_v6(v6dstp, 0, 0, 0, ill->ill_ipif,
-		    &sire, zoneid, 0, match_flags);
+		match_flags |= MATCH_IRE_PARENT | MATCH_IRE_SECATTR;
+		ire = ire_ftable_lookup_v6(v6dstp, NULL, NULL, 0, ill->ill_ipif,
+		    &sire, zoneid, 0, MBLK_GETLABEL(mp), match_flags);
 	}
 
 	ip3dbg(("ip_newroute_v6: ire_ftable_lookup_v6() "
@@ -4403,8 +4529,8 @@
 			 * We check if there are trailing unresolved routes for
 			 * the destination contained in sire.
 			 */
-			multirt_is_resolvable =
-			    ire_multirt_lookup_v6(&ire, &sire, multirt_flags);
+			multirt_is_resolvable = ire_multirt_lookup_v6(&ire,
+			    &sire, multirt_flags, MBLK_GETLABEL(mp));
 
 			ip3dbg(("ip_newroute_v6: multirt_is_resolvable %d, "
 			    "ire %p, sire %p\n",
@@ -4755,6 +4881,19 @@
 			 * and RTF_MULTIRT to propagate these flags from prefix
 			 * to cache.
 			 */
+
+			/*
+			 * Check cached gateway IRE for any security
+			 * attributes; if found, associate the gateway
+			 * credentials group to the destination IRE.
+			 */
+			if ((attrp = save_ire->ire_gw_secattr) != NULL) {
+				mutex_enter(&attrp->igsa_lock);
+				if ((gcgrp = attrp->igsa_gcgrp) != NULL)
+					GCGRP_REFHOLD(gcgrp);
+				mutex_exit(&attrp->igsa_lock);
+			}
+
 			ire = ire_create_v6(
 				v6dstp,			/* dest address */
 				&ipv6_all_ones,		/* mask */
@@ -4772,13 +4911,23 @@
 				ipif_ire->ire_ihandle,	/* Interface handle */
 				sire->ire_flags &	/* flags if any */
 				    (RTF_SETSRC | RTF_MULTIRT),
-				&(sire->ire_uinfo));
+				&(sire->ire_uinfo),
+				NULL,
+				gcgrp);
 
 			if (ire == NULL) {
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
 				ire_refrele(save_ire);
 				ire_refrele(ipif_ire);
 				break;
 			}
+
+			/* reference now held by IRE */
+			gcgrp = NULL;
+
 			ire->ire_marks |= ire_marks;
 
 			/*
@@ -4871,6 +5020,24 @@
 			}
 			if (dlureq_mp == NULL)
 				break;
+			/*
+			 * TSol note: We are creating the ire cache for the
+			 * destination 'dst'. If 'dst' is offlink, going
+			 * through the first hop 'gw', the security attributes
+			 * of 'dst' must be set to point to the gateway
+			 * credentials of gateway 'gw'. If 'dst' is onlink, it
+			 * is possible that 'dst' is a potential gateway that is
+			 * referenced by some route that has some security
+			 * attributes. Thus in the former case, we need to do a
+			 * gcgrp_lookup of 'gw' while in the latter case we
+			 * need to do gcgrp_lookup of 'dst' itself.
+			 */
+			ga.ga_af = AF_INET6;
+			if (!IN6_IS_ADDR_UNSPECIFIED(&v6gw))
+				ga.ga_addr = v6gw;
+			else
+				ga.ga_addr = *v6dstp;
+			gcgrp = gcgrp_lookup(&ga, B_FALSE);
 
 			/*
 			 * Note: the new ire inherits sire flags RTF_SETSRC
@@ -4896,16 +5063,25 @@
 				(sire != NULL) ?	/* flags if any */
 				    sire->ire_flags &
 				    (RTF_SETSRC | RTF_MULTIRT) : 0,
-				&(save_ire->ire_uinfo));
+				&(save_ire->ire_uinfo),
+				NULL,
+				gcgrp);
 
 			if (dst_ill->ill_phys_addr_length == IPV6_ADDR_LEN)
 				freeb(dlureq_mp);
 
 			if (ire == NULL) {
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
 				ire_refrele(save_ire);
 				break;
 			}
 
+			/* reference now held by IRE */
+			gcgrp = NULL;
+
 			ire->ire_marks |= ire_marks;
 
 			if (!IN6_IS_ADDR_UNSPECIFIED(&v6gw))
@@ -4997,6 +5173,7 @@
 			 * found a resolver that can help.
 			 */
 			dst = *v6dstp;
+
 			/*
 			 * To be at this point in the code with a non-zero gw
 			 * means that dst is reachable through a gateway that
@@ -5012,6 +5189,13 @@
 				dst = v6gw;
 				v6gw = ipv6_all_zeros;
 			}
+			/*
+			 * TSol note: Please see the note above the
+			 * IRE_IF_NORESOLVER case.
+			 */
+			ga.ga_af = AF_INET6;
+			ga.ga_addr = dst;
+			gcgrp = gcgrp_lookup(&ga, B_FALSE);
 			if (dst_ill->ill_flags & ILLF_XRESOLV) {
 				/*
 				 * Ask the external resolver to do its thing.
@@ -5046,14 +5230,24 @@
 					save_ire->ire_ihandle,
 							/* Interface handle */
 					0,		/* flags if any */
-					&(save_ire->ire_uinfo));
+					&(save_ire->ire_uinfo),
+					NULL,
+					gcgrp);
 
 				ire_refrele(save_ire);
 				if (ire == NULL) {
+					if (gcgrp != NULL) {
+						GCGRP_REFRELE(gcgrp);
+						gcgrp = NULL;
+					}
 					ip1dbg(("ip_newroute_v6:"
 					    "ire is NULL\n"));
 					break;
 				}
+
+				/* reference now held by IRE */
+				gcgrp = NULL;
+
 				if ((sire != NULL) &&
 				    (sire->ire_flags & RTF_MULTIRT)) {
 					/*
@@ -5225,13 +5419,22 @@
 				0,
 				save_ire->ire_ihandle,	/* Interface handle */
 				0,			/* flags if any */
-				&(save_ire->ire_uinfo));
+				&(save_ire->ire_uinfo),
+				NULL,
+				gcgrp);
 
 			if (ire == NULL) {
+				if (gcgrp != NULL) {
+					GCGRP_REFRELE(gcgrp);
+					gcgrp = NULL;
+				}
 				ire_refrele(save_ire);
 				break;
 			}
 
+			/* reference now held by IRE */
+			gcgrp = NULL;
+
 			if ((sire != NULL) &&
 			    (sire->ire_flags & RTF_MULTIRT)) {
 				copy_mp = copymsg(first_mp);
@@ -5818,7 +6021,9 @@
 				(fire != NULL) ?
 				(fire->ire_flags & (RTF_SETSRC | RTF_MULTIRT)) :
 				0,
-				&ire_uinfo_null);
+				&ire_uinfo_null,
+				NULL,
+				NULL);
 
 			if (dst_ill->ill_phys_addr_length == IPV6_ADDR_LEN)
 				freeb(dlureq_mp);
@@ -5866,7 +6071,8 @@
 			 */
 			if (copy_mp != NULL) {
 				boolean_t need_resolve =
-					ire_multirt_need_resolve_v6(v6dstp);
+				    ire_multirt_need_resolve_v6(v6dstp,
+					MBLK_GETLABEL(copy_mp));
 				if (!need_resolve) {
 					MULTIRT_DEBUG_UNTAG(copy_mp);
 					freemsg(copy_mp);
@@ -5948,7 +6154,9 @@
 				(fire != NULL) ?
 				(fire->ire_flags & (RTF_SETSRC | RTF_MULTIRT)) :
 				0,
-				&ire_uinfo_null);
+				&ire_uinfo_null,
+				NULL,
+				NULL);
 
 			if (ire == NULL) {
 				ire_refrele(save_ire);
@@ -5994,7 +6202,8 @@
 				 */
 				if (copy_mp != NULL) {
 					boolean_t need_resolve =
-					ire_multirt_need_resolve_v6(v6dstp);
+					    ire_multirt_need_resolve_v6(v6dstp,
+						MBLK_GETLABEL(copy_mp));
 					if (!need_resolve) {
 						MULTIRT_DEBUG_UNTAG(copy_mp);
 						freemsg(copy_mp);
@@ -6071,7 +6280,8 @@
 				 */
 				if (copy_mp != NULL) {
 					boolean_t need_resolve =
-					ire_multirt_need_resolve_v6(v6dstp);
+					    ire_multirt_need_resolve_v6(v6dstp,
+						MBLK_GETLABEL(copy_mp));
 					if (!need_resolve) {
 						MULTIRT_DEBUG_UNTAG(copy_mp);
 						freemsg(copy_mp);
@@ -6195,6 +6405,7 @@
 	uint_t optused;
 	int ret = 0;
 	mblk_t *first_mp;
+	const char *errtype;
 
 	first_mp = mp;
 	if (mp->b_datap->db_type == M_CTL) {
@@ -6208,7 +6419,12 @@
 		} else {
 			if (optlen < 2)
 				goto bad_opt;
-			switch (opt_type) {
+			errtype = "malformed";
+			if (opt_type == ip6opt_ls) {
+				optused = 2 + optptr[1];
+				if (optused > optlen)
+					goto bad_opt;
+			} else switch (opt_type) {
 			case IP6OPT_PADN:
 				/*
 				 * Note:We don't verify that (N-2) pad octets
@@ -6324,16 +6540,22 @@
 				break;
 
 			default:
+				errtype = "unknown";
+				/* FALLTHROUGH */
 			opt_error:
-				ip1dbg(("ip_process_options_v6: bad opt 0x%x\n",
-				    opt_type));
 				switch (IP6OPT_TYPE(opt_type)) {
 				case IP6OPT_TYPE_SKIP:
 					optused = 2 + optptr[1];
 					if (optused > optlen)
 						goto bad_opt;
+					ip1dbg(("ip_process_options_v6: %s "
+					    "opt 0x%x skipped\n",
+					    errtype, opt_type));
 					break;
 				case IP6OPT_TYPE_DISCARD:
+					ip1dbg(("ip_process_options_v6: %s "
+					    "opt 0x%x; packet dropped\n",
+					    errtype, opt_type));
 					freemsg(first_mp);
 					return (-1);
 				case IP6OPT_TYPE_ICMP:
@@ -6350,6 +6572,8 @@
 					    (uint8_t *)ip6h),
 					    B_FALSE, B_TRUE);
 					return (-1);
+				default:
+					ASSERT(0);
 				}
 			}
 		}
@@ -7014,6 +7238,18 @@
 	}
 
 	/*
+	 * Attach any necessary label information to this packet.
+	 */
+	if (is_system_labeled() && !tsol_get_pkt_label(mp, IPV6_VERSION)) {
+		if (ip6opt_ls != 0)
+			ip0dbg(("tsol_get_pkt_label v6 failed\n"));
+		BUMP_MIB(ill->ill_ip6_mib, ipv6InHdrErrors);
+		freemsg(hada_mp);
+		freemsg(first_mp);
+		return;
+	}
+
+	/*
 	 * On incoming v6 multicast packets we will bypass the ire table,
 	 * and assume that the read queue corresponds to the targetted
 	 * interface.
@@ -7084,10 +7320,11 @@
 	 */
 	if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) {
 		ire = ire_ctable_lookup_v6(&ip6h->ip6_dst, NULL,
-		    IRE_CACHE|IRE_LOCAL, ill->ill_ipif, ALL_ZONES,
+		    IRE_CACHE|IRE_LOCAL, ill->ill_ipif, ALL_ZONES, NULL,
 		    MATCH_IRE_TYPE | MATCH_IRE_ILL_GROUP);
 	} else {
-		ire = ire_cache_lookup_v6(&ip6h->ip6_dst, ALL_ZONES);
+		ire = ire_cache_lookup_v6(&ip6h->ip6_dst, ALL_ZONES,
+		    MBLK_GETLABEL(mp));
 	}
 	if (ire == NULL) {
 		/*
@@ -7173,11 +7410,26 @@
 		 */
 		if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src)) {
 			BUMP_MIB(ill->ill_ip6_mib, ipv6ForwProhibits);
-			freemsg(hada_mp);
 			freemsg(mp);
 			ire_refrele(ire);
 			return;
 		}
+
+		if (is_system_labeled()) {
+			mblk_t *mp1;
+
+			if ((mp1 = tsol_ip_forward(ire, mp)) == NULL) {
+				BUMP_MIB(ill->ill_ip6_mib, ipv6ForwProhibits);
+				freemsg(mp);
+				ire_refrele(ire);
+				return;
+			}
+			/* Size may have changed */
+			mp = mp1;
+			ip6h = (ip6_t *)mp->b_rptr;
+			pkt_len = msgdsize(mp);
+		}
+
 		if (pkt_len > ire->ire_max_frag) {
 			BUMP_MIB(ill->ill_ip6_mib, ipv6InTooBigErrors);
 			icmp_pkt2big_v6(WR(q), mp, ire->ire_max_frag,
@@ -7240,7 +7492,8 @@
 
 			src_ire_v6 = ire_ftable_lookup_v6(&ip6h->ip6_src,
 			    NULL, NULL, IRE_INTERFACE, ire->ire_ipif, NULL,
-			    ALL_ZONES, 0, MATCH_IRE_IPIF | MATCH_IRE_TYPE);
+			    ALL_ZONES, 0, NULL,
+			    MATCH_IRE_IPIF | MATCH_IRE_TYPE);
 
 			if (src_ire_v6 != NULL) {
 				/*
@@ -7495,8 +7748,8 @@
 			}
 			sctph->sh_chksum = pktsum;
 			ports = *(uint32_t *)(mp->b_rptr + hdr_len);
-			if ((connp = sctp_find_conn(&ip6h->ip6_src,
-			    &ip6h->ip6_dst, ports, ipif_id, zoneid)) == NULL) {
+			if ((connp = sctp_fanout(&ip6h->ip6_src, &ip6h->ip6_dst,
+			    ports, ipif_id, zoneid, mp)) == NULL) {
 				ip_fanout_sctp_raw(first_mp, ill,
 				    (ipha_t *)ip6h, B_FALSE, ports,
 				    mctl_present,
@@ -8797,7 +9050,8 @@
 			addrptr += (numaddr - (rthdr->ip6r0_segleft + 1));
 			if (addrptr != NULL) {
 				ire = ire_ctable_lookup_v6(addrptr, NULL,
-				    IRE_LOCAL, NULL, ALL_ZONES, MATCH_IRE_TYPE);
+				    IRE_LOCAL, NULL, ALL_ZONES, NULL,
+				    MATCH_IRE_TYPE);
 				if (ire != NULL) {
 					ire_refrele(ire);
 					return (B_TRUE);
@@ -9213,7 +9467,7 @@
 			if (secpolicy_net_rawaccess(cr) != 0) {
 				ire = ire_route_lookup_v6(&ip6h->ip6_src,
 				    0, 0, (IRE_LOCAL|IRE_LOOPBACK), NULL,
-				    NULL, zoneid,
+				    NULL, zoneid, NULL,
 				    MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
 				if (ire == NULL) {
 					if (do_outrequests)
@@ -9415,7 +9669,7 @@
 		 * as it does not really have a real destination to
 		 * talk to.
 		 */
-		ire = ire_cache_lookup_v6(v6dstp, zoneid);
+		ire = ire_cache_lookup_v6(v6dstp, zoneid, MBLK_GETLABEL(mp));
 	} else {
 		/*
 		 * IRE_MARK_CONDEMNED is marked in ire_delete. We don't
@@ -9441,7 +9695,8 @@
 			if (ire != NULL && sctp_ire == NULL)
 				IRE_REFRELE_NOTR(ire);
 
-			ire = (ire_t *)ire_cache_lookup_v6(v6dstp, zoneid);
+			ire = ire_cache_lookup_v6(v6dstp, zoneid,
+			    MBLK_GETLABEL(mp));
 			if (ire != NULL) {
 				IRE_REFHOLD_NOTR(ire);
 
@@ -9519,7 +9774,8 @@
 			 * to initiate additional route resolutions.
 			 */
 			multirt_need_resolve =
-			    ire_multirt_need_resolve_v6(&ire->ire_addr_v6);
+			    ire_multirt_need_resolve_v6(&ire->ire_addr_v6,
+				MBLK_GETLABEL(first_mp));
 			ip2dbg(("ip_wput_v6: ire %p, "
 			    "multirt_need_resolve %d, first_mp %p\n",
 			    (void *)ire, multirt_need_resolve,
@@ -9895,7 +10151,7 @@
 	 *	  It is used only when ire_cache_lookup is used above.
 	 */
 	ire = ire_ctable_lookup_v6(v6dstp, 0, 0, ill->ill_ipif,
-	    zoneid, match_flags);
+	    zoneid, MBLK_GETLABEL(mp), match_flags);
 	if (ire != NULL) {
 		/*
 		 * Check if the ire has the RTF_MULTIRT flag, inherited
@@ -9933,7 +10189,8 @@
 			 * to initiate additional route resolutions.
 			 */
 			multirt_need_resolve =
-			    ire_multirt_need_resolve_v6(&ire->ire_addr_v6);
+			    ire_multirt_need_resolve_v6(&ire->ire_addr_v6,
+				MBLK_GETLABEL(first_mp));
 			ip2dbg(("ip_wput_v6[send_from_ill]: ire %p, "
 			    "multirt_need_resolve %d, first_mp %p\n",
 			    (void *)ire, multirt_need_resolve,
@@ -10413,7 +10670,8 @@
 		ip6h->ip6_hops = ill->ill_max_hops;
 	}
 
-	if (ire->ire_type == IRE_LOCAL && ire->ire_zoneid != zoneid) {
+	if (ire->ire_type == IRE_LOCAL && ire->ire_zoneid != zoneid &&
+	    ire->ire_zoneid != ALL_ZONES) {
 		/*
 		 * When a zone sends a packet to another zone, we try to deliver
 		 * the packet under the same conditions as if the destination
@@ -10423,7 +10681,7 @@
 		 * ip_newroute_v6() does.
 		 */
 		ire_t *src_ire = ire_ftable_lookup_v6(&ip6h->ip6_dst, 0, 0, 0,
-		    NULL, NULL, zoneid, 0, (MATCH_IRE_RECURSIVE |
+		    NULL, NULL, zoneid, 0, NULL, (MATCH_IRE_RECURSIVE |
 		    MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE));
 		if (src_ire != NULL &&
 		    !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))) {
@@ -11422,11 +11680,11 @@
 		 * Unicast case: we match the conn only if it's in the specified
 		 * zone.
 		 */
-		return (connp->conn_zoneid == zoneid);
+		return (connp->conn_zoneid == zoneid || zoneid == ALL_ZONES);
 	}
 
 	if ((fanout_flags & IP_FF_NO_MCAST_LOOP) &&
-	    connp->conn_zoneid == zoneid) {
+	    (connp->conn_zoneid == zoneid || zoneid == ALL_ZONES)) {
 		/*
 		 * Loopback case: the sending endpoint has IP_MULTICAST_LOOP
 		 * disabled, therefore we don't dispatch the multicast packet to
@@ -11436,7 +11694,7 @@
 	}
 
 	if ((ill->ill_phyint->phyint_flags & PHYI_LOOPBACK) &&
-	    connp->conn_zoneid != zoneid) {
+	    connp->conn_zoneid != zoneid && zoneid != ALL_ZONES) {
 		/*
 		 * Multicast packet on the loopback interface: we only match
 		 * conns who joined the group in the specified zone.
@@ -12409,7 +12667,7 @@
 			continue;
 
 		ire_gw = ire_ftable_lookup_v6(&ire->ire_gateway_addr_v6, 0, 0,
-		    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0,
+		    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0, NULL,
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE);
 		/* No resolver exists for the gateway; skip this ire. */
 		if (ire_gw == NULL)
@@ -12546,7 +12804,7 @@
 	    secpolicy_net_rawaccess(cr) != 0) {
 		ire = ire_route_lookup_v6(&pkti->ipi6_addr, 0, 0,
 		    (IRE_LOCAL|IRE_LOOPBACK), NULL, NULL,
-		    connp->conn_zoneid, MATCH_IRE_TYPE);
+		    connp->conn_zoneid, NULL, MATCH_IRE_TYPE);
 		if (ire != NULL)
 			ire_refrele(ire);
 		else
--- a/usr/src/uts/common/inet/ip/ip6_if.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip6_if.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -38,7 +37,6 @@
 #include <sys/stream.h>
 #include <sys/dlpi.h>
 #include <sys/stropts.h>
-#include <sys/strlog.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
 #include <sys/kstat.h>
@@ -48,14 +46,10 @@
 #include <sys/systm.h>
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
 #include <sys/isa_defs.h>
 #include <net/if.h>
-#include <net/if_types.h>
 #include <net/if_dl.h>
 #include <net/route.h>
-#include <sys/sockio.h>
 #include <netinet/in.h>
 #include <netinet/igmp_var.h>
 #include <netinet/ip6.h>
@@ -63,10 +57,8 @@
 #include <netinet/in.h>
 
 #include <inet/common.h>
-#include <inet/mi.h>
 #include <inet/nd.h>
 #include <inet/mib2.h>
-#include <inet/arp.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_multi.h>
@@ -79,8 +71,8 @@
 #include <inet/ipclassifier.h>
 #include <inet/sctp_ip.h>
 
-#include <netinet/igmp.h>
-#include <netinet/ip_mroute.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
 
 static in6_addr_t	ipv6_ll_template =
 			{(uint32_t)V6_LINKLOCAL, 0x0, 0x0, 0x0};
@@ -225,7 +217,9 @@
 		GRAB_CONN_LOCK(q);
 		mutex_enter(&ill->ill_lock);
 		for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
-			if (zoneid != ALL_ZONES && ipif->ipif_zoneid != zoneid)
+			if (zoneid != ALL_ZONES &&
+			    ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			/* Allow the ipif to be down */
 			if ((!ptp && (IN6_ARE_ADDR_EQUAL(
@@ -332,7 +326,8 @@
 int
 ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask,
     const in6_addr_t *gw_addr, const in6_addr_t *src_addr, int flags,
-    ipif_t *ipif_arg, ire_t **ire_arg, queue_t *q, mblk_t *mp, ipsq_func_t func)
+    ipif_t *ipif_arg, ire_t **ire_arg, queue_t *q, mblk_t *mp, ipsq_func_t func,
+    struct rtsa_s *sp)
 {
 	ire_t	*ire;
 	ire_t	*gw_ire = NULL;
@@ -341,6 +336,9 @@
 	uint_t	type;
 	int	match_flags = MATCH_IRE_TYPE;
 	int	error;
+	tsol_gc_t *gc = NULL;
+	tsol_gcgrp_t *gcgrp = NULL;
+	boolean_t gcgrp_xtraref = B_FALSE;
 
 	if (ire_arg != NULL)
 		*ire_arg = NULL;
@@ -433,6 +431,14 @@
 	if (!(flags & RTF_GATEWAY)) {
 		queue_t	*stq;
 
+		if (sp != NULL) {
+			ip2dbg(("ip_rt_add_v6: gateway security attributes "
+			    "cannot be set with interface route\n"));
+			if (ipif_refheld)
+				ipif_refrele(ipif);
+			return (EINVAL);
+		}
+
 		/*
 		 * As the interface index specified with the RTA_IFP sockaddr is
 		 * the same for all ipif's off of an ill, the matching logic
@@ -470,7 +476,7 @@
 		 */
 		match_flags |= MATCH_IRE_MASK;
 		ire = ire_ftable_lookup_v6(dst_addr, mask, 0, IRE_INTERFACE,
-		    ipif, NULL, ALL_ZONES, 0, match_flags);
+		    ipif, NULL, ALL_ZONES, 0, NULL, match_flags);
 		if (ire != NULL) {
 			ire_refrele(ire);
 			if (ipif_refheld)
@@ -501,7 +507,9 @@
 		    0,
 		    0,
 		    flags,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 		if (ire == NULL) {
 			if (ipif_refheld)
 				ipif_refrele(ipif);
@@ -551,7 +559,7 @@
 	if (ipif_arg != NULL)
 		match_flags |= MATCH_IRE_ILL;
 	gw_ire = ire_ftable_lookup_v6(gw_addr, 0, 0, IRE_INTERFACE, ipif_arg,
-	    NULL, ALL_ZONES, 0, match_flags);
+	    NULL, ALL_ZONES, 0, NULL, match_flags);
 	if (gw_ire == NULL)
 		return (ENETUNREACH);
 
@@ -572,13 +580,45 @@
 
 	/* check for a duplicate entry */
 	ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, type, ipif_arg,
-	    NULL, ALL_ZONES, 0, match_flags | MATCH_IRE_MASK | MATCH_IRE_GW);
+	    NULL, ALL_ZONES, 0, NULL,
+	    match_flags | MATCH_IRE_MASK | MATCH_IRE_GW);
 	if (ire != NULL) {
 		ire_refrele(gw_ire);
 		ire_refrele(ire);
 		return (EEXIST);
 	}
 
+	/* Security attribute exists */
+	if (sp != NULL) {
+		tsol_gcgrp_addr_t ga;
+
+		/* find or create the gateway credentials group */
+		ga.ga_af = AF_INET6;
+		ga.ga_addr = *gw_addr;
+
+		/* we hold reference to it upon success */
+		gcgrp = gcgrp_lookup(&ga, B_TRUE);
+		if (gcgrp == NULL) {
+			ire_refrele(gw_ire);
+			return (ENOMEM);
+		}
+
+		/*
+		 * Create and add the security attribute to the group; a
+		 * reference to the group is made upon allocating a new
+		 * entry successfully.  If it finds an already-existing
+		 * entry for the security attribute in the group, it simply
+		 * returns it and no new reference is made to the group.
+		 */
+		gc = gc_create(sp, gcgrp, &gcgrp_xtraref);
+		if (gc == NULL) {
+			/* release reference held by gcgrp_lookup */
+			GCGRP_REFRELE(gcgrp);
+			ire_refrele(gw_ire);
+			return (ENOMEM);
+		}
+	}
+
 	/* Create the IRE. */
 	ire = ire_create_v6(
 	    dst_addr,				/* dest address */
@@ -598,8 +638,19 @@
 	    0,
 	    0,
 	    flags,
-	    &gw_ire->ire_uinfo);		/* Inherit ULP info from gw */
+	    &gw_ire->ire_uinfo,			/* Inherit ULP info from gw */
+	    gc,					/* security attribute */
+	    NULL);
+	/*
+	 * The ire holds a reference to the 'gc' and the 'gc' holds a
+	 * reference to the 'gcgrp'. We can now release the extra reference
+	 * the 'gcgrp' acquired in the gcgrp_lookup, if it was not used.
+	 */
+	if (gcgrp_xtraref)
+		GCGRP_REFRELE(gcgrp);
 	if (ire == NULL) {
+		if (gc != NULL)
+			GC_REFRELE(gc);
 		ire_refrele(gw_ire);
 		return (ENOMEM);
 	}
@@ -646,6 +697,17 @@
 		}
 	}
 
+	/*
+	 * Now that the prefix IRE entry has been created, delete any
+	 * existing gateway IRE cache entries as well as any IRE caches
+	 * using the gateway, and force them to be created through
+	 * ip_newroute_v6.
+	 */
+	if (gc != NULL) {
+		ASSERT(gcgrp != NULL);
+		ire_clookup_delete_cache_gw_v6(gw_addr, ALL_ZONES);
+	}
+
 save_ire:
 	if (gw_ire != NULL) {
 		ire_refrele(gw_ire);
@@ -768,10 +830,10 @@
 
 		if (ipif->ipif_ire_type == IRE_LOOPBACK)
 			ire = ire_ctable_lookup_v6(dst_addr, 0, IRE_LOOPBACK,
-			    ipif, ALL_ZONES, match_flags);
+			    ipif, ALL_ZONES, NULL, match_flags);
 		if (ire == NULL)
 			ire = ire_ftable_lookup_v6(dst_addr, mask, 0,
-			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
+			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0, NULL,
 			    match_flags);
 	} else if (err == EINPROGRESS) {
 		return (err);
@@ -802,11 +864,11 @@
 		else
 			type = IRE_PREFIX;
 		ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, type,
-		    ipif_arg, NULL, ALL_ZONES, 0, match_flags);
+		    ipif_arg, NULL, ALL_ZONES, 0, NULL, match_flags);
 		if (ire == NULL && type == IRE_HOST) {
 			ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr,
 			    IRE_HOST_REDIRECT, ipif_arg, NULL, ALL_ZONES, 0,
-			    match_flags);
+			    NULL, match_flags);
 		}
 	}
 
@@ -1419,7 +1481,9 @@
 		    0,
 		    0,
 		    ifrt->ifrt_flags,
-		    &ifrt->ifrt_iulp_info);
+		    &ifrt->ifrt_iulp_info,
+		    NULL,
+		    NULL);
 		if (ire == NULL) {
 			mutex_exit(&ipif->ipif_saved_ire_lock);
 			kmem_free(ipif_saved_irep,
@@ -1528,6 +1592,7 @@
 #define	cand_srcaddr	cand_ipif->ipif_v6lcl_addr
 #define	cand_flags	cand_ipif->ipif_flags
 #define	cand_ill	cand_ipif->ipif_ill
+#define	cand_zoneid	cand_ipif->ipif_zoneid
 
 /* information about the destination for source address selection */
 typedef struct dstinfo {
@@ -1787,6 +1852,23 @@
 }
 
 /*
+ * Prefer to use zone-specific addresses when possible instead of all-zones
+ * addresses.
+ */
+/* ARGSUSED2 */
+static rule_res_t
+rule_zone_specific(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo)
+{
+	if ((bc->cand_zoneid == ALL_ZONES) ==
+	    (cc->cand_zoneid == ALL_ZONES))
+		return (CAND_TIE);
+	else if (cc->cand_zoneid == ALL_ZONES)
+		return (CAND_AVOID);
+	else
+		return (CAND_PREFER);
+}
+
+/*
  * Determine the best source address given a destination address and a
  * destination ill.  If no suitable source address is found, it returns
  * NULL. If there is a usable address pointed to by the usesrc
@@ -1828,6 +1910,7 @@
 	boolean_t	first_candidate = B_TRUE;
 	rule_res_t	rule_result;
 	phyint_t	*phyi;
+	tsol_tpc_t	*src_rhtp, *dst_rhtp;
 
 	/*
 	 * The list of ordering rules.  They are applied in the order they
@@ -1845,6 +1928,7 @@
 		rule_label,
 		rule_temporary,
 		rule_prefix,
+		rule_zone_specific,
 		NULL
 	};
 
@@ -1868,6 +1952,26 @@
 		dstinfo.dst_ill = dstill;
 	}
 
+	/*
+	 * If we're dealing with an unlabeled destination on a labeled system,
+	 * make sure that we ignore source addresses that are incompatible with
+	 * the destination's default label.  That destination's default label
+	 * must dominate the minimum label on the source address.
+	 *
+	 * (Note that this has to do with Trusted Solaris.  It's not related to
+	 * the labels described by ip6_asp_lookup.)
+	 */
+	dst_rhtp = NULL;
+	if (is_system_labeled()) {
+		dst_rhtp = find_tpc(dst, IPV6_VERSION, B_FALSE);
+		if (dst_rhtp == NULL)
+			return (NULL);
+		if (dst_rhtp->tpc_tp.host_type != UNLABELED) {
+			TPC_RELE(dst_rhtp);
+			dst_rhtp = NULL;
+		}
+	}
+
 	dstinfo.dst_addr = dst;
 	dstinfo.dst_scope = ip_addr_scope_v6(dst);
 	dstinfo.dst_label = ip6_asp_lookup(dst, NULL);
@@ -1936,9 +2040,37 @@
 			if (!IPIF_VALID_IPV6_SOURCE(ipif))
 				continue;
 
-			if (zoneid != ALL_ZONES && ipif->ipif_zoneid != zoneid)
+			if (zoneid != ALL_ZONES &&
+			    ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 
+			/*
+			 * Check compatibility of local address for
+			 * destination's default label if we're on a labeled
+			 * system.  Incompatible addresses can't be used at
+			 * all and must be skipped over.
+			 */
+			if (dst_rhtp != NULL) {
+				boolean_t incompat;
+
+				src_rhtp = find_tpc(&ipif->ipif_v6lcl_addr,
+				    IPV6_VERSION, B_FALSE);
+				if (src_rhtp == NULL)
+					continue;
+				incompat =
+				    src_rhtp->tpc_tp.host_type != SUN_CIPSO ||
+				    src_rhtp->tpc_tp.tp_doi !=
+				    dst_rhtp->tpc_tp.tp_doi ||
+				    (!_blinrange(&dst_rhtp->tpc_tp.tp_def_label,
+				    &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
+				    !blinlset(&dst_rhtp->tpc_tp.tp_def_label,
+				    src_rhtp->tpc_tp.tp_sl_set_cipso));
+				TPC_RELE(src_rhtp);
+				if (incompat)
+					continue;
+			}
+
 			if (first_candidate) {
 				/*
 				 * This is first valid address in the list.
@@ -2014,6 +2146,9 @@
 	if (usesrc_ill != NULL)
 		ill_refrele(usesrc_ill);
 
+	if (dst_rhtp != NULL)
+		TPC_RELE(dst_rhtp);
+
 	if (ipif == NULL) {
 		rw_exit(&ill_g_lock);
 		return (NULL);
@@ -2152,7 +2287,9 @@
 	    0,
 	    0,
 	    0,
-	    &ire_uinfo_null);
+	    &ire_uinfo_null,
+	    NULL,
+	    NULL);
 
 	if (ire != NULL) {
 		ire_t *ret_ire;
@@ -2505,6 +2642,22 @@
 
 	if (!IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr) &&
 	    !(ipif->ipif_flags & IPIF_NOLOCAL)) {
+
+		/*
+		 * If we're on a labeled system then make sure that zone-
+		 * private addresses have proper remote host database entries.
+		 */
+		if (is_system_labeled() &&
+		    ipif->ipif_ire_type != IRE_LOOPBACK) {
+			if (ip6opt_ls == 0) {
+				cmn_err(CE_WARN, "IPv6 not enabled "
+				    "via /etc/system");
+				return (EINVAL);
+			}
+			if (!tsol_check_interface_address(ipif))
+				return (EINVAL);
+		}
+
 		/* Register the source address for __sin6_src_id */
 		err = ip_srcid_insert(&ipif->ipif_v6lcl_addr,
 		    ipif->ipif_zoneid);
@@ -2541,7 +2694,9 @@
 		    0,
 		    0,
 		    (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE : 0,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 	}
 
 	/*
@@ -2581,7 +2736,9 @@
 		    0,
 		    0,
 		    (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE : 0,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 	}
 
 	/*
@@ -2608,7 +2765,7 @@
 		 * this tunnel interface.
 		 */
 		isdup = ire_ftable_lookup_v6(first_addr, &prefix_mask, 0,
-		    IRE_IF_NORESOLVER, ill->ill_ipif, NULL, ALL_ZONES, 0,
+		    IRE_IF_NORESOLVER, ill->ill_ipif, NULL, ALL_ZONES, 0, NULL,
 		    (MATCH_IRE_SRC | MATCH_IRE_MASK));
 
 		if (isdup == NULL) {
@@ -2632,7 +2789,9 @@
 			    0,
 			    0,
 			    RTF_UP,
-			    &ire_uinfo_null);
+			    &ire_uinfo_null,
+			    NULL,
+			    NULL);
 		} else {
 			ire_refrele(isdup);
 		}
--- a/usr/src/uts/common/inet/ip/ip6_ire.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip6_ire.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -35,8 +34,6 @@
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <sys/stropts.h>
-#include <sys/strlog.h>
-#include <sys/dlpi.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
 
@@ -54,16 +51,17 @@
 #include <inet/mi.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
-#include <inet/arp.h>
 #include <inet/ip_ndp.h>
 #include <inet/ip_if.h>
 #include <inet/ip_ire.h>
-#include <inet/ip_rts.h>
 #include <inet/ipclassifier.h>
 #include <inet/nd.h>
 #include <sys/kmem.h>
 #include <sys/zone.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+
 irb_t *ip_forwarding_table_v6[IP6_MASK_TABLE_SIZE];
 /* This is dynamically allocated in ip_ire_init */
 irb_t *ip_cache_table_v6;
@@ -77,8 +75,9 @@
 static	void	ire_report_ftable_v6(ire_t *ire, char *mp);
 static	void	ire_report_ctable_v6(ire_t *ire, char *mp);
 static boolean_t ire_match_args_v6(ire_t *ire, const in6_addr_t *addr,
-    const in6_addr_t *mask, const in6_addr_t *gateway, int type, ipif_t *ipif,
-    zoneid_t zoneid, uint32_t ihandle, int match_flags);
+    const in6_addr_t *mask, const in6_addr_t *gateway, int type,
+    const ipif_t *ipif, zoneid_t zoneid, uint32_t ihandle,
+    const ts_label_t *tsl, int match_flags);
 
 /*
  * Named Dispatch routine to produce a formatted report on all IREs.
@@ -270,8 +269,16 @@
     const in6_addr_t *v6gateway, uint_t *max_fragp,
     mblk_t *fp_mp, queue_t *rfq, queue_t *stq, ushort_t type,
     mblk_t *dlureq_mp, ipif_t *ipif, const in6_addr_t *v6cmask,
-    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info)
+    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info,
+    tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
+	/*
+	 * Reject IRE security attribute creation/initialization
+	 * if system is not running in Trusted mode.
+	 */
+	if ((gc != NULL || gcgrp != NULL) && !is_system_labeled())
+		return (NULL);
+
 	if (fp_mp != NULL) {
 		/*
 		 * We can't dupb() here as multiple threads could be
@@ -321,8 +328,11 @@
 		ire->ire_frag_flag = IPH_FRAG_HDR;
 	}
 
-	ire_init_common(ire, max_fragp, fp_mp, rfq, stq, type, dlureq_mp,
-	    ipif, NULL, phandle, ihandle, flags, IPV6_VERSION, ulp_info);
+	/* ire_init_common will free the mblks upon encountering any failure */
+	if (!ire_init_common(ire, max_fragp, fp_mp, rfq, stq, type, dlureq_mp,
+	    ipif, NULL, phandle, ihandle, flags, IPV6_VERSION, ulp_info,
+	    gc, gcgrp))
+		return (NULL);
 
 	return (ire);
 }
@@ -337,7 +347,8 @@
     const in6_addr_t *v6src_addr, const in6_addr_t *v6gateway,
     mblk_t *fp_mp, queue_t *rfq, queue_t *stq, ushort_t type,
     mblk_t *dlureq_mp, ipif_t *ipif, const in6_addr_t *v6cmask,
-    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info)
+    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info,
+    tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
 	ire_t	*ire;
 	ire_t	*ret_ire;
@@ -362,7 +373,7 @@
 
 	ret_ire = ire_init_v6(ire, v6addr, v6mask, v6src_addr, v6gateway,
 	    NULL, fp_mp, rfq, stq, type, dlureq_mp, ipif, v6cmask, phandle,
-	    ihandle, flags, ulp_info);
+	    ihandle, flags, ulp_info, gc, gcgrp);
 
 	if (ret_ire == NULL) {
 		freeb(ire->ire_mp);
@@ -382,7 +393,8 @@
     const in6_addr_t *v6src_addr, const in6_addr_t *v6gateway,
     uint_t *max_fragp, mblk_t *fp_mp, queue_t *rfq, queue_t *stq, ushort_t type,
     mblk_t *dlureq_mp, ipif_t *ipif, const in6_addr_t *v6cmask,
-    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info)
+    uint32_t phandle, uint32_t ihandle, uint_t flags, const iulp_t *ulp_info,
+    tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
 	ire_t	*ire;
 	ire_t	*ret_ire;
@@ -398,7 +410,7 @@
 
 	ret_ire = ire_init_v6(ire, v6addr, v6mask, v6src_addr, v6gateway,
 	    max_fragp, fp_mp, rfq, stq, type, dlureq_mp, ipif, v6cmask, phandle,
-	    ihandle, flags, ulp_info);
+	    ihandle, flags, ulp_info, gc, gcgrp);
 
 	if (ret_ire == NULL) {
 		kmem_cache_free(ire_cache, ire);
@@ -427,7 +439,7 @@
 	in6_addr_t gw_addr_v6;
 
 	ire = ire_ftable_lookup_v6(group, 0, 0, 0, NULL, NULL,
-	    zoneid, 0, MATCH_IRE_DEFAULT);
+	    zoneid, 0, NULL, MATCH_IRE_DEFAULT);
 
 	/* We search a resolvable ire in case of multirouting. */
 	if ((ire != NULL) && (ire->ire_flags & RTF_MULTIRT)) {
@@ -437,7 +449,8 @@
 		 * may be changed here. In that case, ire_multirt_lookup()
 		 * IRE_REFRELE the original ire and change it.
 		 */
-		(void) ire_multirt_lookup_v6(&cire, &ire, MULTIRT_CACHEGW);
+		(void) ire_multirt_lookup_v6(&cire, &ire, MULTIRT_CACHEGW,
+		    NULL);
 		if (cire != NULL)
 			ire_refrele(cire);
 	}
@@ -466,7 +479,7 @@
 		ire_refrele(ire);
 		ire = ire_ftable_lookup_v6(&gw_addr_v6, 0, 0,
 		    IRE_INTERFACE, ipif, NULL, zoneid, 0,
-		    match_flags);
+		    NULL, match_flags);
 		return (ire);
 	case IRE_IF_NORESOLVER:
 	case IRE_IF_RESOLVER:
@@ -497,7 +510,8 @@
 		rw_enter(&irb->irb_lock, RW_READER);
 		for (ire = irb->irb_ire; ire; ire = ire->ire_next) {
 			if ((ire->ire_marks & IRE_MARK_CONDEMNED) ||
-			    ire->ire_zoneid != zoneid)
+			    ire->ire_zoneid != zoneid &&
+			    ire->ire_zoneid != ALL_ZONES)
 				continue;
 			switch (ire->ire_type) {
 			case IRE_LOOPBACK:
@@ -847,7 +861,8 @@
 			continue;
 		if (ire_match_args_v6(ire1, &ire->ire_addr_v6,
 		    &ire->ire_mask_v6, &ire->ire_gateway_addr_v6,
-		    ire->ire_type, ire->ire_ipif, ire->ire_zoneid, 0, flags)) {
+		    ire->ire_type, ire->ire_ipif, ire->ire_zoneid, 0, NULL,
+		    flags)) {
 			/*
 			 * Return the old ire after doing a REFHOLD.
 			 * As most of the callers continue to use the IRE
@@ -1066,7 +1081,7 @@
 		if (ip_mask_to_plen_v6(&ire->ire_mask_v6) == IPV6_ABITS) {
 			ire_t *lire;
 			lire = ire_ctable_lookup_v6(&ire->ire_addr_v6, NULL,
-			    IRE_CACHE, NULL, ALL_ZONES, MATCH_IRE_TYPE);
+			    IRE_CACHE, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (lire != NULL) {
 				ire_refrele(lire);
 				ire_flush_cache_v6(ire, IRE_FLUSH_ADD);
@@ -1385,8 +1400,8 @@
  */
 static boolean_t
 ire_match_args_v6(ire_t *ire, const in6_addr_t *addr, const in6_addr_t *mask,
-    const in6_addr_t *gateway, int type, ipif_t *ipif, zoneid_t zoneid,
-    uint32_t ihandle, int match_flags)
+    const in6_addr_t *gateway, int type, const ipif_t *ipif, zoneid_t zoneid,
+    uint32_t ihandle, const ts_label_t *tsl, int match_flags)
 {
 	in6_addr_t masked_addr;
 	in6_addr_t gw_addr_v6;
@@ -1416,7 +1431,8 @@
 	    (ire->ire_marks & IRE_MARK_HIDDEN))
 		return (B_FALSE);
 
-	if (zoneid != ALL_ZONES && zoneid != ire->ire_zoneid) {
+	if (zoneid != ALL_ZONES && zoneid != ire->ire_zoneid &&
+	    ire->ire_zoneid != ALL_ZONES) {
 		/*
 		 * If MATCH_IRE_ZONEONLY has been set and the supplied zoneid is
 		 * valid and does not match that of ire_zoneid, a failure to
@@ -1486,7 +1502,8 @@
 			    tipif != NULL; tipif = tipif->ipif_next) {
 				if (IPIF_CAN_LOOKUP(tipif) &&
 				    (tipif->ipif_flags & IPIF_UP) &&
-				    (tipif->ipif_zoneid == zoneid))
+				    (tipif->ipif_zoneid == zoneid ||
+				    tipif->ipif_zoneid == ALL_ZONES))
 					break;
 			}
 			mutex_exit(&ire->ire_ipif->ipif_ill->ill_lock);
@@ -1541,7 +1558,10 @@
 	    ((!(match_flags & MATCH_IRE_ILL_GROUP)) ||
 		(ire_ill == ipif_ill) ||
 		(ire_ill_group != NULL &&
-		ire_ill_group == ipif_ill_group))) {
+		ire_ill_group == ipif_ill_group)) &&
+	    ((!(match_flags & MATCH_IRE_SECATTR)) ||
+		(!is_system_labeled()) ||
+		(tsol_ire_match_gwattr(ire, tsl) == 0))) {
 		/* We found the matched IRE */
 		return (B_TRUE);
 	}
@@ -1553,8 +1573,8 @@
  */
 ire_t *
 ire_route_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask,
-    const in6_addr_t *gateway, int type, ipif_t *ipif, ire_t **pire,
-    zoneid_t zoneid, int flags)
+    const in6_addr_t *gateway, int type, const ipif_t *ipif, ire_t **pire,
+    zoneid_t zoneid, const ts_label_t *tsl, int flags)
 {
 	ire_t *ire = NULL;
 
@@ -1576,13 +1596,13 @@
 	 */
 	if ((flags & MATCH_IRE_TYPE) == 0 || (type & IRE_CACHETABLE) != 0) {
 		ire = ire_ctable_lookup_v6(addr, gateway, type, ipif, zoneid,
-		    flags);
+		    tsl, flags);
 		if (ire != NULL)
 			return (ire);
 	}
 	if ((flags & MATCH_IRE_TYPE) == 0 || (type & IRE_FORWARDTABLE) != 0) {
 		ire = ire_ftable_lookup_v6(addr, mask, gateway, type, ipif,
-		    pire, zoneid, 0, flags);
+		    pire, zoneid, 0, tsl, flags);
 	}
 	return (ire);
 }
@@ -1620,8 +1640,8 @@
  */
 ire_t *
 ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask,
-    const in6_addr_t *gateway, int type, ipif_t *ipif, ire_t **pire,
-    zoneid_t zoneid, uint32_t ihandle, int flags)
+    const in6_addr_t *gateway, int type, const ipif_t *ipif, ire_t **pire,
+    zoneid_t zoneid, uint32_t ihandle, const ts_label_t *tsl, int flags)
 {
 	irb_t *irb_ptr;
 	ire_t	*rire;
@@ -1671,7 +1691,7 @@
 			if (ire->ire_marks & IRE_MARK_CONDEMNED)
 				continue;
 			if (ire_match_args_v6(ire, addr, mask, gateway, type,
-			    ipif, zoneid, ihandle, flags))
+			    ipif, zoneid, ihandle, tsl, flags))
 				goto found_ire;
 		}
 		rw_exit(&irb_ptr->irb_lock);
@@ -1697,7 +1717,7 @@
 					continue;
 				if (ire_match_args_v6(ire, addr,
 				    &ire->ire_mask_v6, gateway, type, ipif,
-				    zoneid, ihandle, flags))
+				    zoneid, ihandle, tsl, flags))
 					goto found_ire;
 			}
 			rw_exit(&irb_ptr->irb_lock);
@@ -1732,7 +1752,7 @@
 
 				if (ire_match_args_v6(ire, addr,
 				    &ipv6_all_zeros, gateway, type, ipif,
-				    zoneid, ihandle, flags))
+				    zoneid, ihandle, tsl, flags))
 					goto found_ire;
 			}
 			rw_exit(&irb_ptr->irb_lock);
@@ -1815,7 +1835,7 @@
 
 			if (ire_match_args_v6(ire, addr,
 			    &ipv6_all_zeros, gateway, type, ipif,
-			    zoneid, ihandle, flags)) {
+			    zoneid, ihandle, tsl, flags)) {
 				int match_flags;
 
 				/*
@@ -1831,9 +1851,10 @@
 				mutex_enter(&ire->ire_lock);
 				gw_addr_v6 = ire->ire_gateway_addr_v6;
 				mutex_exit(&ire->ire_lock);
-				match_flags = MATCH_IRE_ILL_GROUP;
+				match_flags = MATCH_IRE_ILL_GROUP |
+				    MATCH_IRE_SECATTR;
 				rire = ire_ctable_lookup_v6(&gw_addr_v6, NULL,
-				    0, ire->ire_ipif, zoneid, match_flags);
+				    0, ire->ire_ipif, zoneid, tsl, match_flags);
 				if (rire != NULL) {
 					nce = rire->ire_nce;
 					if (nce != NULL &&
@@ -1867,7 +1888,7 @@
 					 */
 					rire = ire_route_lookup_v6(&gw_addr_v6,
 					    NULL, NULL, 0, ire->ire_ipif, NULL,
-					    zoneid, match_flags);
+					    zoneid, tsl, match_flags);
 					if (rire != NULL) {
 						ire_refrele(rire);
 						saved_ire = ire;
@@ -1903,7 +1924,7 @@
 
 				if (ire_match_args_v6(ire, addr,
 				    &ipv6_all_zeros, gateway, type, ipif,
-				    zoneid, ihandle, flags)) {
+				    zoneid, ihandle, tsl, flags)) {
 					IRE_REFHOLD(ire);
 					IRB_REFRELE(irb_ptr);
 					goto found_ire_held;
@@ -1937,7 +1958,7 @@
 	 * of lookup is done.
 	 */
 	if (flags & MATCH_IRE_RECURSIVE) {
-		ipif_t	*gw_ipif;
+		const ipif_t *gw_ipif;
 		int match_flags = MATCH_IRE_DSTONLY;
 
 		if (ire->ire_type & IRE_INTERFACE)
@@ -1971,7 +1992,7 @@
 		mutex_exit(&ire->ire_lock);
 
 		ire = ire_route_lookup_v6(&gw_addr_v6, NULL, NULL, 0,
-		    ire->ire_ipif, NULL, zoneid, match_flags);
+		    ire->ire_ipif, NULL, zoneid, tsl, match_flags);
 		if (ire == NULL) {
 			/*
 			 * In this case we have to deal with the
@@ -2018,7 +2039,7 @@
 		ire_refrele(ire);
 		ire = ire_route_lookup_v6(&gw_addr_v6, NULL, NULL,
 		    (IRE_CACHETABLE | IRE_INTERFACE), gw_ipif, NULL, zoneid,
-		    match_flags);
+		    NULL, match_flags);
 		if (ire == NULL) {
 			/*
 			 * In this case we have to deal with the
@@ -2061,6 +2082,34 @@
 }
 
 /*
+ * Delete the IRE cache for the gateway and all IRE caches whose
+ * ire_gateway_addr_v6 points to this gateway, and allow them to
+ * be created on demand by ip_newroute_v6.
+ */
+void
+ire_clookup_delete_cache_gw_v6(const in6_addr_t *addr, zoneid_t zoneid)
+{
+	irb_t *irb;
+	ire_t *ire;
+
+	irb = &ip_cache_table_v6[IRE_ADDR_HASH_V6(*addr, ip6_cache_table_size)];
+	IRB_REFHOLD(irb);
+	for (ire = irb->irb_ire; ire != NULL; ire = ire->ire_next) {
+		if (ire->ire_marks & IRE_MARK_CONDEMNED)
+			continue;
+
+		ASSERT(IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones));
+		if (ire_match_args_v6(ire, addr, &ire->ire_mask_v6, 0,
+		    IRE_CACHE, NULL, zoneid, 0, NULL, MATCH_IRE_TYPE)) {
+			ire_delete(ire);
+		}
+	}
+	IRB_REFRELE(irb);
+
+	ire_walk_v6(ire_delete_cache_gw_v6, (char *)addr, zoneid);
+}
+
+/*
  * Looks up cache table for a route.
  * specific lookup can be indicated by
  * passing the MATCH_* flags and the
@@ -2068,7 +2117,8 @@
  */
 ire_t *
 ire_ctable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *gateway,
-    int type, ipif_t *ipif, zoneid_t zoneid, int flags)
+    int type, const ipif_t *ipif, zoneid_t zoneid, const ts_label_t *tsl,
+    int flags)
 {
 	ire_t *ire;
 	irb_t *irb_ptr;
@@ -2092,7 +2142,7 @@
 
 		ASSERT(IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones));
 		if (ire_match_args_v6(ire, addr, &ire->ire_mask_v6, gateway,
-		    type, ipif, zoneid, 0, flags)) {
+		    type, ipif, zoneid, 0, tsl, flags)) {
 			IRE_REFHOLD(ire);
 			rw_exit(&irb_ptr->irb_lock);
 			return (ire);
@@ -2108,7 +2158,8 @@
  * to the hidden ones.
  */
 ire_t *
-ire_cache_lookup_v6(const in6_addr_t *addr, zoneid_t zoneid)
+ire_cache_lookup_v6(const in6_addr_t *addr, zoneid_t zoneid,
+    const ts_label_t *tsl)
 {
 	irb_t *irb_ptr;
 	ire_t *ire;
@@ -2120,7 +2171,19 @@
 		if (ire->ire_marks & (IRE_MARK_CONDEMNED|IRE_MARK_HIDDEN))
 			continue;
 		if (IN6_ARE_ADDR_EQUAL(&ire->ire_addr_v6, addr)) {
+			/*
+			 * Finally, check if the security policy has any
+			 * restriction on using this route for the specified
+			 * message.
+			 */
+			if (tsl != NULL &&
+			    ire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(ire, tsl) != 0) {
+				continue;
+			}
+
 			if (zoneid == ALL_ZONES || ire->ire_zoneid == zoneid ||
+			    ire->ire_zoneid == ALL_ZONES ||
 			    ire->ire_type == IRE_LOCAL) {
 				IRE_REFHOLD(ire);
 				rw_exit(&irb_ptr->irb_lock);
@@ -2160,7 +2223,7 @@
 	 */
 	ire = ire_ftable_lookup_v6(&cire->ire_addr_v6, &cire->ire_cmask_v6,
 	    NULL, IRE_INTERFACE, NULL, NULL, ALL_ZONES, cire->ire_ihandle,
-	    match_flags);
+	    NULL, match_flags);
 	if (ire != NULL)
 		return (ire);
 	/*
@@ -2246,7 +2309,7 @@
 	 */
 	ire = ire_ftable_lookup_v6(&cire->ire_addr_v6, &cire->ire_cmask_v6, 0,
 	    IRE_INTERFACE, pire->ire_ipif, NULL, ALL_ZONES, cire->ire_ihandle,
-	    match_flags);
+	    NULL, match_flags);
 	if (ire != NULL)
 		return (ire);
 	/*
@@ -2281,7 +2344,7 @@
 	gw_addr = pire->ire_gateway_addr_v6;
 	mutex_exit(&pire->ire_lock);
 	ire = ire_ftable_lookup_v6(&gw_addr, 0, 0, IRE_OFFSUBNET,
-	    pire->ire_ipif, NULL, ALL_ZONES, 0, match_flags);
+	    pire->ire_ipif, NULL, ALL_ZONES, 0, NULL, match_flags);
 	if (ire == NULL)
 		return (NULL);
 	/*
@@ -2296,7 +2359,8 @@
 
 	match_flags |= MATCH_IRE_IHANDLE;
 	ire = ire_ftable_lookup_v6(&gw_addr, 0, 0, IRE_INTERFACE,
-	    gw_ipif, NULL, ALL_ZONES, cire->ire_ihandle, match_flags);
+	    gw_ipif, NULL, ALL_ZONES, cire->ire_ihandle,
+	    NULL, match_flags);
 	return (ire);
 }
 
@@ -2313,24 +2377,25 @@
  * (Sometimes called as writer though not required by this function.)
  */
 ire_t *
-ipif_to_ire_v6(ipif_t *ipif)
+ipif_to_ire_v6(const ipif_t *ipif)
 {
 	ire_t	*ire;
 
 	ASSERT(ipif->ipif_isv6);
 	if (ipif->ipif_ire_type == IRE_LOOPBACK) {
 		ire = ire_ctable_lookup_v6(&ipif->ipif_v6lcl_addr, NULL,
-		    IRE_LOOPBACK, ipif, ALL_ZONES,
+		    IRE_LOOPBACK, ipif, ALL_ZONES, NULL,
 		    (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 	} else if (ipif->ipif_flags & IPIF_POINTOPOINT) {
 		/* In this case we need to lookup destination address. */
 		ire = ire_ftable_lookup_v6(&ipif->ipif_v6pp_dst_addr,
 		    &ipv6_all_ones, NULL, IRE_INTERFACE, ipif, NULL, ALL_ZONES,
-		    0, (MATCH_IRE_TYPE | MATCH_IRE_IPIF | MATCH_IRE_MASK));
+		    0, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF |
+		    MATCH_IRE_MASK));
 	} else {
 		ire = ire_ftable_lookup_v6(&ipif->ipif_v6subnet,
 		    &ipif->ipif_v6net_mask, NULL, IRE_INTERFACE, ipif, NULL,
-		    ALL_ZONES, 0, (MATCH_IRE_TYPE | MATCH_IRE_IPIF |
+		    ALL_ZONES, 0, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF |
 		    MATCH_IRE_MASK));
 	}
 	return (ire);
@@ -2342,7 +2407,7 @@
  * This only works in the global zone.
  */
 boolean_t
-ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp)
+ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp, const ts_label_t *tsl)
 {
 	ire_t	*first_fire;
 	ire_t	*first_cire;
@@ -2355,7 +2420,8 @@
 
 	/* Retrieve the first IRE_HOST that matches the destination */
 	first_fire = ire_ftable_lookup_v6(v6dstp, &ipv6_all_ones, 0, IRE_HOST,
-	    NULL, NULL, ALL_ZONES, 0, MATCH_IRE_MASK | MATCH_IRE_TYPE);
+	    NULL, NULL, ALL_ZONES, 0, tsl, MATCH_IRE_MASK | MATCH_IRE_TYPE |
+	    MATCH_IRE_SECATTR);
 
 	/* No route at all */
 	if (first_fire == NULL) {
@@ -2366,7 +2432,7 @@
 	ASSERT(firb);
 
 	/* Retrieve the first IRE_CACHE ire for that destination. */
-	first_cire = ire_cache_lookup_v6(v6dstp, GLOBAL_ZONEID);
+	first_cire = ire_cache_lookup_v6(v6dstp, GLOBAL_ZONEID, tsl);
 
 	/* No resolved route. */
 	if (first_cire == NULL) {
@@ -2407,7 +2473,7 @@
 	/* At least one route is unresolved; search for a resolvable route. */
 	if (unres_cnt > 0)
 		resolvable = ire_multirt_lookup_v6(&first_cire, &first_fire,
-		    MULTIRT_USESTAMP|MULTIRT_CACHEGW);
+		    MULTIRT_USESTAMP|MULTIRT_CACHEGW, tsl);
 
 	if (first_fire)
 		ire_refrele(first_fire);
@@ -2427,7 +2493,8 @@
  * This only works in the global zone.
  */
 boolean_t
-ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags)
+ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags,
+    const ts_label_t *tsl)
 {
 	clock_t	delta;
 	ire_t	*best_fire = NULL;
@@ -2473,7 +2540,7 @@
 	 * if we don't find one, no route for that dest is
 	 * resolved yet.
 	 */
-	first_cire = ire_cache_lookup_v6(&v6dst, GLOBAL_ZONEID);
+	first_cire = ire_cache_lookup_v6(&v6dst, GLOBAL_ZONEID, tsl);
 	if (first_cire) {
 		cirb = first_cire->ire_bucket;
 	}
@@ -2499,6 +2566,11 @@
 			if (!IN6_ARE_ADDR_EQUAL(&fire->ire_addr_v6, &v6dst))
 				continue;
 
+			if (fire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(fire, tsl) != 0) {
+				continue;
+			}
+
 			mutex_enter(&fire->ire_lock);
 			v6gw = fire->ire_gateway_addr_v6;
 			mutex_exit(&fire->ire_lock);
@@ -2532,6 +2604,13 @@
 					    (IRE_MARK_CONDEMNED|
 						IRE_MARK_HIDDEN))
 						continue;
+
+					if (cire->ire_gw_secattr != NULL &&
+					    tsol_ire_match_gwattr(cire,
+					    tsl) != 0) {
+						continue;
+					}
+
 					/*
 					 * Check if the IRE_CACHE's gateway
 					 * matches the IRE_HOST's gateway.
@@ -2562,7 +2641,8 @@
 			 * for the gateway?
 			 */
 			gw_ire = ire_route_lookup_v6(&v6gw, 0, 0, 0, NULL, NULL,
-			    ALL_ZONES, MATCH_IRE_RECURSIVE);
+			    ALL_ZONES, tsl, MATCH_IRE_RECURSIVE |
+			    MATCH_IRE_SECATTR);
 
 			ip2dbg(("ire_multirt_lookup_v6: looked up gw_ire %p\n",
 			    (void *)gw_ire));
@@ -2684,6 +2764,11 @@
 			if (!IN6_ARE_ADDR_EQUAL(&fire->ire_addr_v6, &v6dst))
 				continue;
 
+			if (fire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(fire, tsl) != 0) {
+				continue;
+			}
+
 			already_resolved = B_FALSE;
 
 			mutex_enter(&fire->ire_lock);
@@ -2691,8 +2776,9 @@
 			mutex_exit(&fire->ire_lock);
 
 			gw_ire = ire_ftable_lookup_v6(&v6gw, 0, 0,
-			    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0,
-			    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE);
+			    IRE_INTERFACE, NULL, NULL, ALL_ZONES, 0, tsl,
+			    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE |
+			    MATCH_IRE_SECATTR);
 
 			/* No resolver for the gateway; we skip this ire. */
 			if (gw_ire == NULL) {
@@ -2719,6 +2805,13 @@
 					    (IRE_MARK_CONDEMNED|
 						IRE_MARK_HIDDEN))
 						continue;
+
+					if (cire->ire_gw_secattr != NULL &&
+					    tsol_ire_match_gwattr(cire,
+					    tsl) != 0) {
+						continue;
+					}
+
 					/*
 					 * Cache entries are linked to the
 					 * parent routes using the parent handle
@@ -2843,7 +2936,7 @@
 	int	match_flags = MATCH_IRE_TYPE | MATCH_IRE_ILL;
 
 	ire = ire_ftable_lookup_v6(v6dstp, 0, 0, 0, NULL, NULL, ALL_ZONES, 0,
-	    MATCH_IRE_DEFAULT);
+	    NULL, MATCH_IRE_DEFAULT);
 
 	if (ire == NULL)
 		return (NULL);
@@ -2855,7 +2948,8 @@
 	ire_refrele(ire);
 	for (ire = irb->irb_ire; ire != NULL; ire = ire->ire_next) {
 		if (!IN6_ARE_ADDR_EQUAL(&ire->ire_addr_v6, v6dstp) ||
-		    ipif->ipif_zoneid != ire->ire_zoneid) {
+		    (ipif->ipif_zoneid != ire->ire_zoneid &&
+		    ire->ire_zoneid != ALL_ZONES)) {
 			continue;
 		}
 
@@ -2868,7 +2962,7 @@
 			mutex_exit(&ire->ire_lock);
 			gw_ire = ire_ftable_lookup_v6(&v6gw, 0, 0,
 			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
-			    match_flags);
+			    NULL, match_flags);
 
 			if (gw_ire != NULL) {
 				if (save_ire != NULL) {
--- a/usr/src/uts/common/inet/ip/ip6_rts.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip6_rts.c	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 1992-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -72,6 +72,8 @@
 #include <inet/ip_ire.h>
 #include <inet/ip_rts.h>
 #include <inet/ip_multi.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
 
 /*
  * Fills the message with the given info.
@@ -80,7 +82,8 @@
 rts_fill_msg_v6(int type, int rtm_addrs, const in6_addr_t *dst,
     const in6_addr_t *mask, const in6_addr_t *gateway,
     const in6_addr_t *src_addr, const in6_addr_t *brd_addr,
-    const in6_addr_t *author, ipif_t *ipif, mblk_t *mp)
+    const in6_addr_t *author, const ipif_t *ipif, mblk_t *mp,
+    uint_t sacnt, const tsol_gc_t *gc)
 {
 	rt_msghdr_t	*rtm;
 	sin6_t		*sin6;
@@ -89,6 +92,7 @@
 	int		i;
 
 	ASSERT(mp != NULL);
+	ASSERT(sacnt == 0 || gc != NULL);
 	/*
 	 * First find the type of the message
 	 * and its length.
@@ -98,7 +102,7 @@
 	 * Now find the size of the data
 	 * that follows the message header.
 	 */
-	data_size = rts_data_msg_size(rtm_addrs, AF_INET6);
+	data_size = rts_data_msg_size(rtm_addrs, AF_INET6, sacnt);
 
 	rtm = (rt_msghdr_t *)mp->b_rptr;
 	mp->b_wptr = &mp->b_rptr[header_size];
@@ -147,6 +151,32 @@
 			break;
 		}
 	}
+
+	if (gc != NULL) {
+		rtm_ext_t *rtm_ext;
+		struct rtsa_s *rp_dst;
+		tsol_rtsecattr_t *rsap;
+		int i;
+
+		ASSERT(gc->gc_grp != NULL);
+		ASSERT(RW_LOCK_HELD(&gc->gc_grp->gcgrp_rwlock));
+		ASSERT(sacnt > 0);
+
+		rtm_ext = (rtm_ext_t *)cp;
+		rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR;
+		rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(sacnt);
+
+		rsap = (tsol_rtsecattr_t *)(rtm_ext + 1);
+		rsap->rtsa_cnt = sacnt;
+		rp_dst = rsap->rtsa_attr;
+
+		for (i = 0; i < sacnt; i++, gc = gc->gc_next, rp_dst++) {
+			ASSERT(gc->gc_db != NULL);
+			bcopy(&gc->gc_db->gcdb_attr, rp_dst, sizeof (*rp_dst));
+		}
+		cp = (uchar_t *)rp_dst;
+	}
+
 	mp->b_wptr = cp;
 	mp->b_cont = NULL;
 	/*
@@ -176,11 +206,11 @@
 
 	if (rtm_addrs == 0)
 		return;
-	mp = rts_alloc_msg(type, rtm_addrs, AF_INET6);
+	mp = rts_alloc_msg(type, rtm_addrs, AF_INET6, 0);
 	if (mp == NULL)
 		return;
 	rts_fill_msg_v6(type, rtm_addrs, dst_addr, net_mask, gw_addr, source,
-	    &ipv6_all_zeros, author, NULL, mp);
+	    &ipv6_all_zeros, author, NULL, mp, 0, NULL);
 	rtm = (rt_msghdr_t *)mp->b_rptr;
 	rtm->rtm_flags = flags;
 	rtm->rtm_errno = error;
--- a/usr/src/uts/common/inet/ip/ip_if.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Fri Mar 24 12:29:20 2006 -0800
@@ -48,8 +48,6 @@
 #include <sys/systm.h>
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
 #include <sys/isa_defs.h>
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -92,13 +90,15 @@
 
 #include <netinet/igmp.h>
 #include <inet/ip_listutils.h>
-#include <netinet/ip_mroute.h>
 #include <inet/ipclassifier.h>
 #include <sys/mac.h>
 
 #include <sys/systeminfo.h>
 #include <sys/bootconf.h>
 
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
+
 /* The character which tells where the ill_name ends */
 #define	IPIF_SEPARATOR_CHAR	':'
 
@@ -4553,7 +4553,7 @@
  * creates datalink socket info from the device.
  */
 int
-ill_dls_info(struct sockaddr_dl *sdl, ipif_t *ipif)
+ill_dls_info(struct sockaddr_dl *sdl, const ipif_t *ipif)
 {
 	size_t	length;
 	ill_t	*ill = ipif->ipif_ill;
@@ -5096,7 +5096,8 @@
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
 			if (zoneid != GLOBAL_ZONEID &&
-			    zoneid != ipif->ipif_zoneid)
+			    zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			(void) mi_mpprintf(mp,
 			    MI_COL_PTRFMT_STR
@@ -5484,7 +5485,9 @@
 		mutex_enter(&ill->ill_lock);
 		for (ipif = ill->ill_ipif; ipif != NULL;
 		    ipif = ipif->ipif_next) {
-			if (zoneid != ALL_ZONES && zoneid != ipif->ipif_zoneid)
+			if (zoneid != ALL_ZONES &&
+			    zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			/* Allow the ipif to be down */
 			if ((!ptp && (ipif->ipif_lcl_addr == addr) &&
@@ -5557,7 +5560,8 @@
 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
 		if (!IPIF_CAN_LOOKUP(ipif))
 			continue;
-		if (zoneid != ALL_ZONES && zoneid != ipif->ipif_zoneid)
+		if (zoneid != ALL_ZONES && zoneid != ipif->ipif_zoneid &&
+		    ipif->ipif_zoneid != ALL_ZONES)
 			continue;
 		/* Allow the ipif to be down */
 		if (ipif->ipif_flags & IPIF_POINTOPOINT) {
@@ -5576,7 +5580,7 @@
 	}
 	mutex_exit(&ill->ill_lock);
 	ire = ire_route_lookup(addr, 0, 0, 0, NULL, NULL, zoneid,
-	    MATCH_IRE_RECURSIVE);
+	    NULL, MATCH_IRE_RECURSIVE);
 	if (ire != NULL) {
 		/*
 		 * The callers of this function wants to know the
@@ -6160,7 +6164,7 @@
 ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr,
     ipaddr_t src_addr, int flags, ipif_t *ipif_arg, ipif_t *src_ipif,
     ire_t **ire_arg, boolean_t ioctl_msg, queue_t *q, mblk_t *mp,
-    ipsq_func_t func)
+    ipsq_func_t func, struct rtsa_s *sp)
 {
 	ire_t	*ire;
 	ire_t	*gw_ire = NULL;
@@ -6169,6 +6173,9 @@
 	uint_t	type;
 	int	match_flags = MATCH_IRE_TYPE;
 	int	error;
+	tsol_gc_t *gc = NULL;
+	tsol_gcgrp_t *gcgrp = NULL;
+	boolean_t gcgrp_xtraref = B_FALSE;
 
 	ip1dbg(("ip_rt_add:"));
 
@@ -6280,6 +6287,14 @@
 		queue_t	*rfq = NULL;
 		ill_t	*in_ill = NULL;
 
+		if (sp != NULL) {
+			ip2dbg(("ip_rt_add: gateway security attributes "
+			    "cannot be set with interface route\n"));
+			if (ipif_refheld)
+				ipif_refrele(ipif);
+			return (EINVAL);
+		}
+
 		/*
 		 * As the interface index specified with the RTA_IFP sockaddr is
 		 * the same for all ipif's off of an ill, the matching logic
@@ -6335,7 +6350,7 @@
 		} else {
 			ire = ire_ftable_lookup(dst_addr, mask, 0,
 			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
-			    match_flags);
+			    NULL, match_flags);
 		}
 		if (ire != NULL) {
 			ire_refrele(ire);
@@ -6381,7 +6396,9 @@
 		    0,
 		    0,
 		    flags,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 		if (ire == NULL) {
 			if (ipif_refheld)
 				ipif_refrele(ipif);
@@ -6437,7 +6454,7 @@
 	if (ipif_arg != NULL)
 		match_flags |= MATCH_IRE_ILL;
 	gw_ire = ire_ftable_lookup(gw_addr, 0, 0, IRE_INTERFACE, ipif_arg, NULL,
-	    ALL_ZONES, 0, match_flags);
+	    ALL_ZONES, 0, NULL, match_flags);
 	if (gw_ire == NULL)
 		return (ENETUNREACH);
 
@@ -6458,13 +6475,45 @@
 
 	/* check for a duplicate entry */
 	ire = ire_ftable_lookup(dst_addr, mask, gw_addr, type, ipif_arg,
-	    NULL, ALL_ZONES, 0, match_flags | MATCH_IRE_MASK | MATCH_IRE_GW);
+	    NULL, ALL_ZONES, 0, NULL,
+	    match_flags | MATCH_IRE_MASK | MATCH_IRE_GW);
 	if (ire != NULL) {
 		ire_refrele(gw_ire);
 		ire_refrele(ire);
 		return (EEXIST);
 	}
 
+	/* Security attribute exists */
+	if (sp != NULL) {
+		tsol_gcgrp_addr_t ga;
+
+		/* find or create the gateway credentials group */
+		ga.ga_af = AF_INET;
+		IN6_IPADDR_TO_V4MAPPED(gw_addr, &ga.ga_addr);
+
+		/* we hold reference to it upon success */
+		gcgrp = gcgrp_lookup(&ga, B_TRUE);
+		if (gcgrp == NULL) {
+			ire_refrele(gw_ire);
+			return (ENOMEM);
+		}
+
+		/*
+		 * Create and add the security attribute to the group; a
+		 * reference to the group is made upon allocating a new
+		 * entry successfully.  If it finds an already-existing
+		 * entry for the security attribute in the group, it simply
+		 * returns it and no new reference is made to the group.
+		 */
+		gc = gc_create(sp, gcgrp, &gcgrp_xtraref);
+		if (gc == NULL) {
+			/* release reference held by gcgrp_lookup */
+			GCGRP_REFRELE(gcgrp);
+			ire_refrele(gw_ire);
+			return (ENOMEM);
+		}
+	}
+
 	/* Create the IRE. */
 	ire = ire_create(
 	    (uchar_t *)&dst_addr,		/* dest address */
@@ -6486,8 +6535,19 @@
 	    0,
 	    0,
 	    flags,
-	    &gw_ire->ire_uinfo);		/* Inherit ULP info from gw */
+	    &gw_ire->ire_uinfo,			/* Inherit ULP info from gw */
+	    gc,					/* security attribute */
+	    NULL);
+	/*
+	 * The ire holds a reference to the 'gc' and the 'gc' holds a
+	 * reference to the 'gcgrp'. We can now release the extra reference
+	 * the 'gcgrp' acquired in the gcgrp_lookup, if it was not used.
+	 */
+	if (gcgrp_xtraref)
+		GCGRP_REFRELE(gcgrp);
 	if (ire == NULL) {
+		if (gc != NULL)
+			GC_REFRELE(gc);
 		ire_refrele(gw_ire);
 		return (ENOMEM);
 	}
@@ -6521,7 +6581,7 @@
 		 * or a multicast.
 		 */
 		ire_t *ire_dst = ire_ctable_lookup(ire->ire_addr, 0,
-		    IRE_BROADCAST, NULL, NULL, MATCH_IRE_TYPE);
+		    IRE_BROADCAST, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 		if (ire_dst != NULL) {
 			ip_cgtp_bcast_add(ire, ire_dst);
 			ire_refrele(ire_dst);
@@ -6541,6 +6601,17 @@
 		}
 	}
 
+	/*
+	 * Now that the prefix IRE entry has been created, delete any
+	 * existing gateway IRE cache entries as well as any IRE caches
+	 * using the gateway, and force them to be created through
+	 * ip_newroute.
+	 */
+	if (gc != NULL) {
+		ASSERT(gcgrp != NULL);
+		ire_clookup_delete_cache_gw(gw_addr, ALL_ZONES);
+	}
+
 save_ire:
 	if (gw_ire != NULL) {
 		ire_refrele(gw_ire);
@@ -6682,12 +6753,13 @@
 		} else {
 			if (ipif->ipif_ire_type == IRE_LOOPBACK) {
 				ire = ire_ctable_lookup(dst_addr, 0,
-				    IRE_LOOPBACK, ipif, ALL_ZONES, match_flags);
+				    IRE_LOOPBACK, ipif, ALL_ZONES, NULL,
+				    match_flags);
 			}
 			if (ire == NULL) {
 				ire = ire_ftable_lookup(dst_addr, mask, 0,
 				    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
-				    match_flags);
+				    NULL, match_flags);
 			}
 		}
 	}
@@ -6723,11 +6795,11 @@
 			else
 				type = IRE_PREFIX;
 			ire = ire_ftable_lookup(dst_addr, mask, gw_addr, type,
-			    ipif_arg, NULL, ALL_ZONES, 0, match_flags);
+			    ipif_arg, NULL, ALL_ZONES, 0, NULL, match_flags);
 			if (ire == NULL && type == IRE_HOST) {
 				ire = ire_ftable_lookup(dst_addr, mask, gw_addr,
 				    IRE_HOST_REDIRECT, ipif_arg, NULL,
-				    ALL_ZONES, 0, match_flags);
+				    ALL_ZONES, 0, NULL, match_flags);
 			}
 		}
 	}
@@ -6810,8 +6882,8 @@
 		mask = ip_subnet_mask(dst_addr, &ipif);
 	}
 
-	error = ip_rt_add(dst_addr, mask, gw_addr, 0, rt->rt_flags,
-	    NULL, NULL, NULL, B_TRUE, q, mp, ip_process_ioctl);
+	error = ip_rt_add(dst_addr, mask, gw_addr, 0, rt->rt_flags, NULL, NULL,
+	    NULL, B_TRUE, q, mp, ip_process_ioctl, NULL);
 	if (ipif != NULL)
 		ipif_refrele(ipif);
 	return (error);
@@ -7791,7 +7863,8 @@
 	while (ill != NULL) {
 		for (ipif = ill->ill_ipif; ipif != NULL;
 		    ipif = ipif->ipif_next) {
-			if (ipif->ipif_zoneid == zoneid)
+			if (ipif->ipif_zoneid == zoneid ||
+			    ipif->ipif_zoneid == ALL_ZONES)
 				numifs++;
 		}
 		ill = ill_next(&ctx, ill);
@@ -7840,6 +7913,7 @@
 				continue;
 
 			if (zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES &&
 			    (zoneid != GLOBAL_ZONEID ||
 			    !(lifn_flags & LIFC_ALLZONES)))
 				continue;
@@ -8027,7 +8101,8 @@
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		for (ipif = ill->ill_ipif; ipif;
 		    ipif = ipif->ipif_next) {
-			if (zoneid != ipif->ipif_zoneid)
+			if (zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			if ((uchar_t *)&ifr[1] > mp1->b_wptr) {
 				if (iocp->ioc_cmd == O_SIOCGIFCONF) {
@@ -8313,6 +8388,7 @@
 				continue;
 
 			if (zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES &&
 			    (zoneid != GLOBAL_ZONEID ||
 			    !(flags & LIFC_ALLZONES)))
 				continue;
@@ -8529,10 +8605,10 @@
 		if (isipv4) {
 			IN6_V4MAPPED_TO_IPADDR(daddr, v4daddr);
 			ire = ire_ftable_lookup(v4daddr, NULL, NULL,
-			    0, NULL, NULL, zoneid, 0, match_ire);
+			    0, NULL, NULL, zoneid, 0, NULL, match_ire);
 		} else {
 			ire = ire_ftable_lookup_v6(daddr, NULL, NULL,
-			    0, NULL, NULL, zoneid, 0, match_ire);
+			    0, NULL, NULL, zoneid, 0, NULL, match_ire);
 		}
 		if (ire == NULL) {
 			dir->dir_dreachable = 0;
@@ -8622,14 +8698,14 @@
 			    v4_addr);
 			ire = ire_ctable_lookup(v4_addr, 0,
 			    IRE_LOCAL|IRE_LOOPBACK, NULL, zoneid,
-			    MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
+			    NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
 		} else {
 			in6_addr_t v6addr;
 
 			v6addr = sin6->sin6_addr;
 			ire = ire_ctable_lookup_v6(&v6addr, 0,
 			    IRE_LOCAL|IRE_LOOPBACK, NULL, zoneid,
-			    MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
+			    NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
 		}
 		break;
 	}
@@ -8639,7 +8715,7 @@
 		v4addr = sin->sin_addr.s_addr;
 		ire = ire_ctable_lookup(v4addr, 0,
 		    IRE_LOCAL|IRE_LOOPBACK, NULL, zoneid,
-		    MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
+		    NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY);
 		break;
 	}
 	default:
@@ -8705,7 +8781,8 @@
 			    v4_addr);
 			if (!CLASSD(v4_addr)) {
 				ire = ire_route_lookup(v4_addr, 0, 0, 0,
-				    NULL, NULL, zoneid, MATCH_IRE_GW);
+				    NULL, NULL, zoneid, NULL,
+				    MATCH_IRE_GW);
 			}
 		} else {
 			in6_addr_t v6addr;
@@ -8716,7 +8793,7 @@
 			if (!IN6_IS_ADDR_MULTICAST(&v6addr)) {
 				ire = ire_route_lookup_v6(&v6addr, 0,
 				    &v6gw, 0, NULL, NULL, zoneid,
-				    MATCH_IRE_GW);
+				    NULL, MATCH_IRE_GW);
 			}
 		}
 		break;
@@ -8727,7 +8804,8 @@
 		v4addr = sin->sin_addr.s_addr;
 		if (!CLASSD(v4addr)) {
 			ire = ire_route_lookup(v4addr, 0, 0, 0,
-			    NULL, NULL, zoneid, MATCH_IRE_GW);
+			    NULL, NULL, zoneid, NULL,
+			    MATCH_IRE_GW);
 		}
 		break;
 	}
@@ -9082,7 +9160,7 @@
 		 * as an extended BSD ioctl. The kernel uses the IP address
 		 * to figure out the network interface.
 		 */
-		ire = ire_cache_lookup(sin->sin_addr.s_addr, ALL_ZONES);
+		ire = ire_cache_lookup(sin->sin_addr.s_addr, ALL_ZONES, NULL);
 		if ((ire == NULL) || (ire->ire_type == IRE_LOOPBACK) ||
 		    ((ill = ire_to_ill(ire)) == NULL) ||
 		    (ill->ill_net_type != IRE_IF_RESOLVER)) {
@@ -9090,7 +9168,7 @@
 				ire_refrele(ire);
 			ire = ire_ftable_lookup(sin->sin_addr.s_addr,
 			    0, 0, IRE_IF_RESOLVER, NULL, NULL, ALL_ZONES, 0,
-			    MATCH_IRE_TYPE);
+			    NULL, MATCH_IRE_TYPE);
 			if ((ire == NULL) ||
 			    ((ill = ire_to_ill(ire)) == NULL)) {
 				if (ire != NULL)
@@ -9167,14 +9245,14 @@
 	 * be rare enough since IRE cache entries have a longer
 	 * life expectancy than ARP cache entries.
 	 */
-	ire = ire_cache_lookup(sin->sin_addr.s_addr, ALL_ZONES);
+	ire = ire_cache_lookup(sin->sin_addr.s_addr, ALL_ZONES, NULL);
 	if ((ire == NULL) || (ire->ire_type == IRE_LOOPBACK) ||
 	    ((ill = ire_to_ill(ire)) == NULL)) {
 		if (ire != NULL)
 			ire_refrele(ire);
 		ire = ire_ftable_lookup(sin->sin_addr.s_addr,
 		    0, 0, IRE_IF_RESOLVER, NULL, NULL, ALL_ZONES, 0,
-		    MATCH_IRE_TYPE);
+		    NULL, MATCH_IRE_TYPE);
 		if ((ire == NULL) || ((ill = ire_to_ill(ire)) == NULL)) {
 			if (ire != NULL)
 				ire_refrele(ire);
@@ -9851,10 +9929,10 @@
 			ipsqill = ill;
 			ire = ire_ctable_lookup(addr, 0, IRE_CACHE,
 			    ipsqill->ill_ipif, ALL_ZONES,
-			    MATCH_IRE_TYPE | MATCH_IRE_ILL);
+			    NULL, MATCH_IRE_TYPE | MATCH_IRE_ILL);
 		} else {
 			ire = ire_ctable_lookup(addr, 0, IRE_CACHE,
-			    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+			    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (ire != NULL)
 				ipsqill = ire_to_ill(ire);
 		}
@@ -11591,7 +11669,8 @@
 		 * in the group has its own broadcast ire.
 		 */
 		ire = ire_ctable_lookup(addr, 0, IRE_BROADCAST,
-		    ipif, ALL_ZONES, (MATCH_IRE_ILL | MATCH_IRE_TYPE));
+		    ipif, ALL_ZONES, NULL,
+		    (MATCH_IRE_ILL | MATCH_IRE_TYPE));
 		if (ire == NULL) {
 			return (EINVAL);
 		} else {
@@ -13990,7 +14069,7 @@
 	 */
 	for (;;) {
 		ire = ire_ctable_lookup(addr, 0, IRE_BROADCAST, ill->ill_ipif,
-		    ALL_ZONES, MATCH_IRE_TYPE | MATCH_IRE_ILL);
+		    ALL_ZONES, NULL, MATCH_IRE_TYPE | MATCH_IRE_ILL);
 		if (ire == NULL)
 			break;
 
@@ -14035,7 +14114,9 @@
 		    ire->ire_phandle,
 		    ire->ire_ihandle,
 		    ire->ire_flags,
-		    &ire->ire_uinfo) == NULL) {
+		    &ire->ire_uinfo,
+		    NULL,
+		    NULL) == NULL) {
 			cmn_err(CE_PANIC, "ire_init() failed");
 		}
 		ire_delete(ire);
@@ -14142,7 +14223,7 @@
 	ASSERT(ill->ill_group == NULL);
 
 	ire = ire_ctable_lookup(addr, 0, IRE_BROADCAST, ill->ill_ipif,
-	    ALL_ZONES, MATCH_IRE_TYPE | MATCH_IRE_ILL);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE | MATCH_IRE_ILL);
 
 	if (ire != NULL) {
 		/*
@@ -14194,7 +14275,7 @@
 	boolean_t fallback = B_FALSE;
 
 	ire = ire_ctable_lookup(addr, 0, IRE_BROADCAST, NULL, ALL_ZONES,
-	    MATCH_IRE_TYPE);
+	    NULL, MATCH_IRE_TYPE);
 	/*
 	 * We may not be able to find some ires if a previous
 	 * ire_create failed. This happens when an ipif goes
@@ -14337,7 +14418,9 @@
 		    clear_ire->ire_phandle,
 		    clear_ire->ire_ihandle,
 		    clear_ire->ire_flags,
-		    &clear_ire->ire_uinfo) == NULL)
+		    &clear_ire->ire_uinfo,
+		    NULL,
+		    NULL) == NULL)
 			cmn_err(CE_PANIC, "ire_init() failed");
 		if (clear_ire->ire_stq == NULL) {
 			ire_t *ire_next = clear_ire->ire_next;
@@ -14368,7 +14451,9 @@
 				    clear_ire_stq->ire_phandle,
 				    clear_ire_stq->ire_ihandle,
 				    clear_ire_stq->ire_flags,
-				    &clear_ire_stq->ire_uinfo) == NULL)
+				    &clear_ire_stq->ire_uinfo,
+				    NULL,
+				    NULL) == NULL)
 					cmn_err(CE_PANIC, "ire_init() failed");
 			}
 		}
@@ -17957,7 +18042,7 @@
  * "ill_name" otherwise.
  */
 char *
-ipif_get_name(ipif_t *ipif, char *buf, int len)
+ipif_get_name(const ipif_t *ipif, char *buf, int len)
 {
 	char	lbuf[32];
 	char	*name;
@@ -18082,7 +18167,8 @@
 	for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
 		if (ipif->ipif_id == id) {
 			if (zoneid != ALL_ZONES &&
-			    zoneid != ipif->ipif_zoneid) {
+			    zoneid != ipif->ipif_zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES) {
 				mutex_exit(&ill->ill_lock);
 				RELEASE_CONN_LOCK(q);
 				ill_refrele(ill);
@@ -18489,7 +18575,9 @@
 		    0,
 		    0,
 		    ifrt->ifrt_flags,
-		    &ifrt->ifrt_iulp_info);
+		    &ifrt->ifrt_iulp_info,
+		    NULL,
+		    NULL);
 
 		if (ire == NULL) {
 			mutex_exit(&ipif->ipif_saved_ire_lock);
@@ -18631,6 +18719,7 @@
 					continue;
 				else if (new_ipif->ipif_zoneid !=
 				    ipif->ipif_zoneid &&
+				    ipif->ipif_zoneid != ALL_ZONES &&
 				    (ill->ill_phyint->phyint_flags &
 				    PHYI_LOOPBACK))
 					continue;
@@ -18963,6 +19052,16 @@
 	/* Create all the IREs associated with this interface */
 	if ((ipif->ipif_lcl_addr != INADDR_ANY) &&
 	    !(ipif->ipif_flags & IPIF_NOLOCAL)) {
+
+		/*
+		 * If we're on a labeled system then make sure that zone-
+		 * private addresses have proper remote host database entries.
+		 */
+		if (is_system_labeled() &&
+		    ipif->ipif_ire_type != IRE_LOOPBACK &&
+		    !tsol_check_interface_address(ipif))
+			return (EINVAL);
+
 		/* Register the source address for __sin6_src_id */
 		err = ip_srcid_insert(&ipif->ipif_v6lcl_addr,
 		    ipif->ipif_zoneid);
@@ -18970,6 +19069,7 @@
 			ip0dbg(("ipif_up_done: srcid_insert %d\n", err));
 			return (err);
 		}
+
 		/* If the interface address is set, create the local IRE. */
 		ip1dbg(("ipif_up_done: 0x%p creating IRE 0x%x for 0x%x\n",
 			(void *)ipif,
@@ -18994,7 +19094,9 @@
 		    0,
 		    (ipif->ipif_flags & IPIF_PRIVATE) ?
 		    RTF_PRIVATE : 0,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 	} else {
 		ip1dbg((
 		    "ipif_up_done: not creating IRE %d for 0x%x: flags 0x%x\n",
@@ -19057,7 +19159,9 @@
 		    0,
 		    0,
 		    (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE: 0,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 	}
 
 	/*
@@ -19239,7 +19343,7 @@
 
 			ire = ire_ctable_lookup(ipif->ipif_brd_addr, 0,
 			    IRE_BROADCAST, ipif, ALL_ZONES,
-			    (MATCH_IRE_TYPE | MATCH_IRE_ILL));
+			    NULL, (MATCH_IRE_TYPE | MATCH_IRE_ILL));
 
 			if (ire == NULL) {
 				/*
@@ -19606,7 +19710,9 @@
 	boolean_t wrapped = B_FALSE;
 	boolean_t same_subnet_only = B_FALSE;
 	boolean_t ipif_same_found, ipif_other_found;
+	boolean_t specific_found;
 	ill_t	*till, *usill = NULL;
+	tsol_tpc_t *src_rhtp, *dst_rhtp;
 
 	if (ill->ill_usesrc_ifindex != 0) {
 		usill = ill_lookup_on_ifindex(ill->ill_usesrc_ifindex, B_FALSE,
@@ -19618,6 +19724,23 @@
 	}
 
 	/*
+	 * If we're dealing with an unlabeled destination on a labeled system,
+	 * make sure that we ignore source addresses that are incompatible with
+	 * the destination's default label.  That destination's default label
+	 * must dominate the minimum label on the source address.
+	 */
+	dst_rhtp = NULL;
+	if (is_system_labeled()) {
+		dst_rhtp = find_tpc(&dst, IPV4_VERSION, B_FALSE);
+		if (dst_rhtp == NULL)
+			return (NULL);
+		if (dst_rhtp->tpc_tp.host_type != UNLABELED) {
+			TPC_RELE(dst_rhtp);
+			dst_rhtp = NULL;
+		}
+	}
+
+	/*
 	 * Holds the ill_g_lock as reader. This makes sure that no ipif/ill
 	 * can be deleted. But an ipif/ill can get CONDEMNED any time.
 	 * After selecting the right ipif, under ill_lock make sure ipif is
@@ -19691,6 +19814,7 @@
 	 *	   one we find that happens to be on the same subnet,
 	 *	   otherwise the first one not in the same subnet.
 	 */
+	specific_found = B_FALSE;
 	for (; till != NULL; till = till->ill_group_next) {
 		ipif_same_found = B_FALSE;
 		ipif_other_found = B_FALSE;
@@ -19703,7 +19827,8 @@
 				continue;
 			if (!(ipif->ipif_flags & IPIF_UP))
 				continue;
-			if (ipif->ipif_zoneid != zoneid)
+			if (ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			/*
 			 * Interfaces with 0.0.0.0 address are allowed to be UP,
@@ -19711,6 +19836,51 @@
 			 */
 			if (ipif->ipif_lcl_addr == INADDR_ANY)
 				continue;
+
+			/*
+			 * Check compatibility of local address for
+			 * destination's default label if we're on a labeled
+			 * system.  Incompatible addresses can't be used at
+			 * all.
+			 */
+			if (dst_rhtp != NULL) {
+				boolean_t incompat;
+
+				src_rhtp = find_tpc(&ipif->ipif_lcl_addr,
+				    IPV4_VERSION, B_FALSE);
+				if (src_rhtp == NULL)
+					continue;
+				incompat =
+				    src_rhtp->tpc_tp.host_type != SUN_CIPSO ||
+				    src_rhtp->tpc_tp.tp_doi !=
+				    dst_rhtp->tpc_tp.tp_doi ||
+				    (!_blinrange(&dst_rhtp->tpc_tp.tp_def_label,
+				    &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
+				    !blinlset(&dst_rhtp->tpc_tp.tp_def_label,
+				    src_rhtp->tpc_tp.tp_sl_set_cipso));
+				TPC_RELE(src_rhtp);
+				if (incompat)
+					continue;
+			}
+
+			/*
+			 * We prefer not to use all all-zones addresses, if we
+			 * can avoid it, as they pose problems with unlabeled
+			 * destinations.
+			 */
+			if (ipif->ipif_zoneid != ALL_ZONES) {
+				if (!specific_found &&
+				    (!same_subnet_only ||
+				    (ipif->ipif_net_mask & dst) ==
+				    ipif->ipif_subnet)) {
+					index = 0;
+					specific_found = B_TRUE;
+					ipif_other_found = B_FALSE;
+				}
+			} else {
+				if (specific_found)
+					continue;
+			}
 			if (ipif->ipif_flags & IPIF_DEPRECATED) {
 				if (ipif_dep == NULL ||
 				    (ipif->ipif_net_mask & dst) ==
@@ -19720,14 +19890,13 @@
 			}
 			if ((ipif->ipif_net_mask & dst) == ipif->ipif_subnet) {
 				/* found a source address in the same subnet */
-				if (same_subnet_only == B_FALSE) {
+				if (!same_subnet_only) {
 					same_subnet_only = B_TRUE;
 					index = 0;
 				}
 				ipif_same_found = B_TRUE;
 			} else {
-				if (same_subnet_only == B_TRUE ||
-				    ipif_other_found == B_TRUE)
+				if (same_subnet_only || ipif_other_found)
 					continue;
 				ipif_other_found = B_TRUE;
 			}
@@ -19736,7 +19905,7 @@
 				wrapped = B_TRUE;
 				index = 0;
 			}
-			if (ipif_same_found == B_TRUE)
+			if (ipif_same_found)
 				break;
 		}
 	}
@@ -19763,6 +19932,8 @@
 	rw_exit(&ill_g_lock);
 	if (usill != NULL)
 		ill_refrele(usill);
+	if (dst_rhtp != NULL)
+		TPC_RELE(dst_rhtp);
 
 #ifdef DEBUG
 	if (ipif == NULL) {
@@ -19896,7 +20067,9 @@
 	    0,
 	    0,
 	    0,
-	    &ire_uinfo_null);
+	    &ire_uinfo_null,
+	    NULL,
+	    NULL);
 
 	if (ire != NULL) {
 		ire_t *ret_ire;
@@ -20086,10 +20259,10 @@
 		return;
 
 	test_allzero_ire = ire_ctable_lookup(0, 0, IRE_BROADCAST,
-	    test_ipif, ALL_ZONES, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
+	    test_ipif, ALL_ZONES, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 
 	test_allone_ire = ire_ctable_lookup(INADDR_BROADCAST, 0, IRE_BROADCAST,
-	    test_ipif, ALL_ZONES, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
+	    test_ipif, ALL_ZONES, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 
 	test_net_mask = ip_net_mask(test_ipif->ipif_subnet);
 	test_subnet_mask = test_ipif->ipif_net_mask;
@@ -20105,14 +20278,14 @@
 	 */
 	test_net_addr = test_net_mask  & test_ipif->ipif_subnet;
 	test_net_ire = ire_ctable_lookup(test_net_addr, 0, IRE_BROADCAST,
-	    test_ipif, ALL_ZONES, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
+	    test_ipif, ALL_ZONES, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 
 	/*
 	 * Check if there is a subnet broadcast IRE associated with this ipif
 	 */
 	test_subnet_addr = test_subnet_mask  & test_ipif->ipif_subnet;
 	test_subnet_ire = ire_ctable_lookup(test_subnet_addr, 0, IRE_BROADCAST,
-	    test_ipif, ALL_ZONES, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
+	    test_ipif, ALL_ZONES, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 
 	/*
 	 * No broadcast ire's associated with this ipif.
@@ -20503,7 +20676,8 @@
 			    ipif = ipif->ipif_next) {
 				if (IPIF_CAN_LOOKUP(ipif) &&
 				    (zoneid == ALL_ZONES ||
-				    zoneid == ipif->ipif_zoneid)) {
+				    zoneid == ipif->ipif_zoneid ||
+				    ipif->ipif_zoneid == ALL_ZONES)) {
 					ipif_refhold_locked(ipif);
 					mutex_exit(&ill->ill_lock);
 					RELEASE_CONN_LOCK(q);
@@ -20756,13 +20930,17 @@
 	zone_status_t status;
 	zoneid_t zoneid;
 
+	ASSERT(ipip->ipi_cmd_type == LIF_CMD);
+	if ((zoneid = lifr->lifr_zoneid) == ALL_ZONES) {
+		if (!is_system_labeled())
+			return (ENOTSUP);
+		zoneid = GLOBAL_ZONEID;
+	}
+
 	/* cannot assign instance zero to a non-global zone */
-	if (ipif->ipif_id == 0)
+	if (ipif->ipif_id == 0 && zoneid != GLOBAL_ZONEID)
 		return (ENOTSUP);
 
-	ASSERT(ipip->ipi_cmd_type == LIF_CMD);
-	zoneid = lifr->lifr_zoneid;
-
 	/*
 	 * Cannot assign to a zone that doesn't exist or is shutting down.  In
 	 * the event of a race with the zone shutdown processing, since IP
@@ -20795,7 +20973,7 @@
 		need_up = B_TRUE;
 	}
 
-	err = ip_sioctl_slifzone_tail(ipif, zoneid, q, mp, need_up);
+	err = ip_sioctl_slifzone_tail(ipif, lifr->lifr_zoneid, q, mp, need_up);
 	return (err);
 }
 
@@ -20840,7 +21018,8 @@
 
 	ASSERT(ipif->ipif_id != 0);
 	ASSERT(ipip->ipi_cmd_type == LIF_CMD);
-	zoneid = lifr->lifr_zoneid;
+	if ((zoneid = lifr->lifr_zoneid) == ALL_ZONES)
+		zoneid = GLOBAL_ZONEID;
 
 	ip1dbg(("ip_sioctl_slifzone_restart(%s:%u %p)\n",
 	    ipif->ipif_ill->ill_name, ipif->ipif_id, (void *)ipif));
@@ -20877,7 +21056,8 @@
 
 	ipif_down_tail(ipif);
 
-	return (ip_sioctl_slifzone_tail(ipif, zoneid, q, mp, B_TRUE));
+	return (ip_sioctl_slifzone_tail(ipif, lifr->lifr_zoneid, q, mp,
+	    B_TRUE));
 }
 
 /* ARGSUSED */
@@ -21885,7 +22065,9 @@
 	    0,
 	    0,
 	    flags,
-	    &ire_uinfo_null);
+	    &ire_uinfo_null,
+	    NULL,
+	    NULL);
 
 	if (ire == NULL)
 		return (ENOMEM);
@@ -21977,7 +22159,8 @@
 		    ipif = ipif->ipif_next) {
 			if (!IPIF_CAN_LOOKUP(ipif))
 				continue;
-			if (ipif->ipif_zoneid != zoneid)
+			if (ipif->ipif_zoneid != zoneid &&
+			    ipif->ipif_zoneid != ALL_ZONES)
 				continue;
 			/*
 			 * Point-to-point case. Look for exact match with
@@ -22104,7 +22287,7 @@
 	ASSERT(ire_dst != NULL);
 
 	ire_prim = ire_ctable_lookup(ire->ire_gateway_addr, 0,
-	    IRE_BROADCAST, NULL, NULL, MATCH_IRE_TYPE);
+	    IRE_BROADCAST, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	if (ire_prim != NULL) {
 		/*
 		 * We are in the special case of broadcasts for
@@ -22142,7 +22325,9 @@
 		    0,
 		    0,
 		    ire->ire_flags,
-		    &ire_uinfo_null);
+		    &ire_uinfo_null,
+		    NULL,
+		    NULL);
 
 		if (bcast_ire != NULL) {
 
@@ -22172,12 +22357,12 @@
 
 	ASSERT(ire != NULL);
 	ire_dst = ire_ctable_lookup(ire->ire_addr, 0, IRE_BROADCAST,
-	    NULL, NULL, MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 	if (ire_dst != NULL) {
 		ire_t *ire_prim;
 
 		ire_prim = ire_ctable_lookup(ire->ire_gateway_addr, 0,
-		    IRE_BROADCAST, NULL, NULL, MATCH_IRE_TYPE);
+		    IRE_BROADCAST, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 		if (ire_prim != NULL) {
 			ipif_t *ipif_prim;
 			ire_t  *bcast_ire;
@@ -22192,7 +22377,7 @@
 			bcast_ire = ire_ctable_lookup(ire->ire_addr,
 			    ire->ire_gateway_addr,
 			    IRE_BROADCAST,
-			    ipif_prim,
+			    ipif_prim, ALL_ZONES,
 			    NULL,
 			    MATCH_IRE_TYPE | MATCH_IRE_GW | MATCH_IRE_IPIF |
 			    MATCH_IRE_MASK);
@@ -22818,7 +23003,8 @@
 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
 		if (!IPIF_CAN_LOOKUP(ipif))
 			continue;
-		if (zoneid != ALL_ZONES && ipif->ipif_zoneid != zoneid)
+		if (zoneid != ALL_ZONES && ipif->ipif_zoneid != zoneid &&
+		    ipif->ipif_zoneid != ALL_ZONES)
 			continue;
 		if ((ipif->ipif_flags & flags) != flags)
 			continue;
--- a/usr/src/uts/common/inet/ip/ip_ire.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_ire.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -35,8 +34,7 @@
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <sys/stropts.h>
-#include <sys/strlog.h>
-#include <sys/dlpi.h>
+#include <sys/strsun.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
 #include <sys/policy.h>
@@ -57,7 +55,6 @@
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_ndp.h>
-#include <inet/arp.h>
 #include <inet/ip_if.h>
 #include <inet/ip_ire.h>
 #include <inet/ip_rts.h>
@@ -71,6 +68,9 @@
 #include <inet/ipclassifier.h>
 #include <sys/zone.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+
 /*
  * Synchronization notes:
  *
@@ -396,18 +396,17 @@
 static void	ire_report_ctable(ire_t *ire, char *mp);
 static void	ire_report_mrtun_table(ire_t *ire, char *mp);
 static void	ire_report_srcif_table(ire_t *ire, char *mp);
-static void	ire_walk_ipvers(pfv_t func, char *arg, uchar_t vers,
+static void	ire_walk_ipvers(pfv_t func, void *arg, uchar_t vers,
     zoneid_t zoneid);
 static void	ire_walk_ill_ipvers(uint_t match_flags, uint_t ire_type,
-		    pfv_t func, char *arg, uchar_t vers, ill_t *ill);
+    pfv_t func, void *arg, uchar_t vers, ill_t *ill);
 static	void	ire_walk_ill_tables(uint_t match_flags, uint_t ire_type,
-		    pfv_t func, char *arg, size_t ftbl_sz, size_t htbl_sz,
-		    irb_t **ipftbl, size_t ctbl_sz, irb_t *ipctbl, ill_t *ill,
-		    zoneid_t zoneid);
+    pfv_t func, void *arg, size_t ftbl_sz, size_t htbl_sz, irb_t **ipftbl,
+    size_t ctbl_sz, irb_t *ipctbl, ill_t *ill, zoneid_t zoneid);
 static void	ire_delete_host_redirects(ipaddr_t gateway);
 static boolean_t ire_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask,
-		    ipaddr_t gateway, int type, ipif_t *ipif, zoneid_t zoneid,
-		    uint32_t ihandle, int match_flags);
+    ipaddr_t gateway, int type, const ipif_t *ipif, zoneid_t zoneid,
+    uint32_t ihandle, const ts_label_t *tsl, int match_flags);
 static void	ire_cache_cleanup(irb_t *irb, uint32_t threshold, int cnt);
 extern void	ill_unlock_ills(ill_t **list, int cnt);
 static void	ire_fastpath_list_add(ill_t *ill, ire_t *ire);
@@ -506,14 +505,14 @@
 		/* Extract the destination address. */
 		addr = *(ipaddr_t *)addr_ucp;
 		/* Find the corresponding IRE. */
-		ire = ire_cache_lookup(addr, zoneid);
+		ire = ire_cache_lookup(addr, zoneid, NULL);
 		break;
 	}
 	case IPV6_ADDR_LEN: {
 		/* Extract the destination address. */
 		v6addr = *(in6_addr_t *)addr_ucp;
 		/* Find the corresponding IRE. */
-		ire = ire_cache_lookup_v6(&v6addr, zoneid);
+		ire = ire_cache_lookup_v6(&v6addr, zoneid, NULL);
 		break;
 	}
 	default:
@@ -647,7 +646,7 @@
 	bcopy(addr_ucp, &addr, IP_ADDR_LEN);
 
 	/* Try to find the CACHED IRE. */
-	ire = ire_cache_lookup(addr, zoneid);
+	ire = ire_cache_lookup(addr, zoneid, NULL);
 
 	/* Nail it. */
 	if (ire) {
@@ -726,7 +725,7 @@
 	}
 	/* Also look for an IRE_HOST_REDIRECT and remove it if present */
 	ire = ire_route_lookup(addr, 0, 0, IRE_HOST_REDIRECT, NULL, NULL,
-	    ALL_ZONES, MATCH_IRE_TYPE);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 
 	/* Nail it. */
 	if (ire) {
@@ -787,8 +786,8 @@
 	if (zoneid == GLOBAL_ZONEID)
 		zoneid = ALL_ZONES;
 
-	ire_walk_v4(ire_report_ftable, (char *)mp->b_cont, zoneid);
-	ire_walk_v4(ire_report_ctable, (char *)mp->b_cont, zoneid);
+	ire_walk_v4(ire_report_ftable, mp->b_cont, zoneid);
+	ire_walk_v4(ire_report_ctable, mp->b_cont, zoneid);
 
 	return (0);
 }
@@ -922,7 +921,7 @@
 	"ref     ");
 	/*   123 */
 
-	ire_walk_ill_mrtun(0, 0, ire_report_mrtun_table, (char *)mp, NULL);
+	ire_walk_ill_mrtun(0, 0, ire_report_mrtun_table, mp, NULL);
 	return (0);
 }
 
@@ -974,7 +973,7 @@
 	    "type    "
 	    /* ABCDEFGH */
 	    "in/out/forward");
-	ire_walk_srcif_table_v4(ire_report_srcif_table, (char *)mp);
+	ire_walk_srcif_table_v4(ire_report_srcif_table, mp);
 	return (0);
 }
 
@@ -1035,12 +1034,12 @@
 	 */
 	if (inire->ire_ipversion == IPV6_VERSION) {
 		ire = ire_route_lookup_v6(&inire->ire_addr_v6, 0, 0, 0,
-		    NULL, &sire, zoneid,
+		    NULL, &sire, zoneid, NULL,
 		    (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT));
 	} else {
 		ASSERT(inire->ire_ipversion == IPV4_VERSION);
 		ire = ire_route_lookup(inire->ire_addr, 0, 0, 0,
-		    NULL, &sire, zoneid,
+		    NULL, &sire, zoneid, NULL,
 		    (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT));
 	}
 
@@ -1516,7 +1515,7 @@
 			mp = first_mp;
 
 			dst_ire = ire_cache_lookup(ipha->ipha_dst,
-			    ire->ire_zoneid);
+			    ire->ire_zoneid, MBLK_GETLABEL(mp));
 		} else {
 			/*
 			 * Get a pointer to the beginning of the IPv6 header.
@@ -1530,7 +1529,7 @@
 			save_mp = mp;
 			mp = first_mp;
 			dst_ire = ire_cache_lookup_v6(&ip6h->ip6_dst,
-			    ire->ire_zoneid);
+			    ire->ire_zoneid, MBLK_GETLABEL(mp));
 		}
 		if (dst_ire != NULL) {
 			if (dst_ire->ire_flags & RTF_MULTIRT) {
@@ -1663,8 +1662,15 @@
     uchar_t *gateway, uchar_t *in_src_addr, uint_t *max_fragp, mblk_t *fp_mp,
     queue_t *rfq, queue_t *stq, ushort_t type, mblk_t *dlureq_mp, ipif_t *ipif,
     ill_t *in_ill, ipaddr_t cmask, uint32_t phandle, uint32_t ihandle,
-    uint32_t flags, const iulp_t *ulp_info)
+    uint32_t flags, const iulp_t *ulp_info, tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
+	/*
+	 * Reject IRE security attribute creation/initialization
+	 * if system is not running in Trusted mode.
+	 */
+	if ((gc != NULL || gcgrp != NULL) && !is_system_labeled())
+		return (NULL);
+
 	if (fp_mp != NULL) {
 		/*
 		 * We can't dupb() here as multiple threads could be
@@ -1722,8 +1728,11 @@
 	if (type == IRE_CACHE)
 		ire->ire_cmask = cmask;
 
-	ire_init_common(ire, max_fragp, fp_mp, rfq, stq, type, dlureq_mp,
-	    ipif, in_ill, phandle, ihandle, flags, IPV4_VERSION, ulp_info);
+	/* ire_init_common will free the mblks upon encountering any failure */
+	if (!ire_init_common(ire, max_fragp, fp_mp, rfq, stq, type, dlureq_mp,
+	    ipif, in_ill, phandle, ihandle, flags, IPV4_VERSION, ulp_info,
+	    gc, gcgrp))
+		return (NULL);
 
 	return (ire);
 }
@@ -1738,7 +1747,7 @@
     uchar_t *in_src_addr, uint_t max_frag, mblk_t *fp_mp, queue_t *rfq,
     queue_t *stq, ushort_t type, mblk_t *dlureq_mp, ipif_t *ipif, ill_t *in_ill,
     ipaddr_t cmask, uint32_t phandle, uint32_t ihandle, uint32_t flags,
-    const iulp_t *ulp_info)
+    const iulp_t *ulp_info, tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
 	ire_t	*ire;
 	ire_t	*ret_ire;
@@ -1761,7 +1770,7 @@
 
 	ret_ire = ire_init(ire, addr, mask, src_addr, gateway, in_src_addr,
 	    NULL, fp_mp, rfq, stq, type, dlureq_mp, ipif, in_ill, cmask,
-	    phandle, ihandle, flags, ulp_info);
+	    phandle, ihandle, flags, ulp_info, gc, gcgrp);
 
 	if (ret_ire == NULL) {
 		freeb(ire->ire_mp);
@@ -1789,7 +1798,7 @@
     uchar_t *in_src_addr, uint_t *max_fragp, mblk_t *fp_mp, queue_t *rfq,
     queue_t *stq, ushort_t type, mblk_t *dlureq_mp, ipif_t *ipif, ill_t *in_ill,
     ipaddr_t cmask, uint32_t phandle, uint32_t ihandle, uint32_t flags,
-    const iulp_t *ulp_info)
+    const iulp_t *ulp_info, tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
 	ire_t	*ire;
 	ire_t	*ret_ire;
@@ -1803,7 +1812,7 @@
 
 	ret_ire = ire_init(ire, addr, mask, src_addr, gateway, in_src_addr,
 	    max_fragp, fp_mp, rfq, stq, type, dlureq_mp, ipif, in_ill,  cmask,
-	    phandle, ihandle, flags, ulp_info);
+	    phandle, ihandle, flags, ulp_info, gc, gcgrp);
 
 	if (ret_ire == NULL) {
 		kmem_cache_free(ire_cache, ire);
@@ -1817,23 +1826,51 @@
 /*
  * Common to IPv4 and IPv6
  */
-void
+boolean_t
 ire_init_common(ire_t *ire, uint_t *max_fragp, mblk_t *fp_mp,
     queue_t *rfq, queue_t *stq, ushort_t type,
     mblk_t *dlureq_mp, ipif_t *ipif, ill_t *in_ill, uint32_t phandle,
     uint32_t ihandle, uint32_t flags, uchar_t ipversion,
-    const iulp_t *ulp_info)
+    const iulp_t *ulp_info, tsol_gc_t *gc, tsol_gcgrp_t *gcgrp)
 {
 	ire->ire_max_fragp = max_fragp;
 	ire->ire_frag_flag |= (ip_path_mtu_discovery) ? IPH_DF : 0;
 
 	ASSERT(fp_mp == NULL || fp_mp->b_datap->db_type == M_DATA);
-	if (ipif) {
+#ifdef DEBUG
+	if (ipif != NULL) {
 		if (ipif->ipif_isv6)
 			ASSERT(ipversion == IPV6_VERSION);
 		else
 			ASSERT(ipversion == IPV4_VERSION);
 	}
+#endif /* DEBUG */
+
+	/*
+	 * Create/initialize IRE security attribute only in Trusted mode;
+	 * if the passed in gc/gcgrp is non-NULL, we expect that the caller
+	 * has held a reference to it and will release it when this routine
+	 * returns a failure, otherwise we own the reference.  We do this
+	 * prior to initializing the rest IRE fields.
+	 */
+	if (is_system_labeled()) {
+		if ((type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST |
+		    IRE_INTERFACE)) != 0) {
+			/* release references on behalf of caller */
+			if (gc != NULL)
+				GC_REFRELE(gc);
+			if (gcgrp != NULL)
+				GCGRP_REFRELE(gcgrp);
+		} else if (tsol_ire_init_gwattr(ire, ipversion,
+		    gc, gcgrp) != 0) {
+			/* free any caller-allocated mblks upon failure */
+			if (fp_mp != NULL)
+				freeb(fp_mp);
+			if (dlureq_mp != NULL)
+				freeb(dlureq_mp);
+			return (B_FALSE);
+		}
+	}
 
 	ire->ire_fp_mp = fp_mp;
 	ire->ire_dlureq_mp = dlureq_mp;
@@ -1883,6 +1920,8 @@
 #ifdef IRE_DEBUG
 	bzero(ire->ire_trace, sizeof (th_trace_t *) * IP_TR_HASH_MAX);
 #endif
+
+	return (B_TRUE);
 }
 
 /*
@@ -1918,7 +1957,7 @@
 
 	/* If this would be a duplicate, don't bother. */
 	if ((ire = ire_ctable_lookup(addr, 0, IRE_BROADCAST, ipif,
-	    ipif->ipif_zoneid, match_flags)) != NULL) {
+	    ipif->ipif_zoneid, NULL, match_flags)) != NULL) {
 		/*
 		 * We look for non-deprecated (and non-anycast, non-nolocal)
 		 * ipifs as the best choice. ipifs with check_flags matching
@@ -1976,7 +2015,9 @@
 	    0,
 	    0,
 	    0,
-	    &ire_uinfo_null);
+	    &ire_uinfo_null,
+	    NULL,
+	    NULL);
 
 	*irep++ = ire_create(
 		(uchar_t *)&addr,		 /* dest address */
@@ -1996,7 +2037,9 @@
 		0,
 		0,
 		0,
-		&ire_uinfo_null);
+		&ire_uinfo_null,
+		NULL,
+		NULL);
 
 	return (irep);
 }
@@ -2120,7 +2163,7 @@
 		return (B_TRUE);
 
 	ip2dbg(("ire_fastpath_update: trying\n"));
-	mp = arg;
+	mp = (mblk_t *)arg;
 	up = mp->b_rptr;
 	cmplen = mp->b_wptr - up;
 	/* Serialize multiple fast path updates */
@@ -2352,7 +2395,7 @@
 	ipaddr_t gw_addr;
 
 	ire = ire_ftable_lookup(group, 0, 0, 0, NULL, NULL, zoneid,
-	    0, MATCH_IRE_DEFAULT);
+	    0, NULL, MATCH_IRE_DEFAULT);
 
 	/* We search a resolvable ire in case of multirouting. */
 	if ((ire != NULL) && (ire->ire_flags & RTF_MULTIRT)) {
@@ -2362,7 +2405,7 @@
 		 * may be changed here. In that case, ire_multirt_lookup()
 		 * IRE_REFRELE the original ire and change it.
 		 */
-		(void) ire_multirt_lookup(&cire, &ire, MULTIRT_CACHEGW);
+		(void) ire_multirt_lookup(&cire, &ire, MULTIRT_CACHEGW, NULL);
 		if (cire != NULL)
 			ire_refrele(cire);
 	}
@@ -2389,7 +2432,7 @@
 		ire_refrele(ire);
 		ire = ire_ftable_lookup(gw_addr, 0, 0,
 		    IRE_INTERFACE, ipif, NULL, zoneid, 0,
-		    match_flags);
+		    NULL, match_flags);
 		return (ire);
 	case IRE_IF_NORESOLVER:
 	case IRE_IF_RESOLVER:
@@ -2420,7 +2463,8 @@
 		rw_enter(&irb->irb_lock, RW_READER);
 		for (ire = irb->irb_ire; ire != NULL; ire = ire->ire_next) {
 			if ((ire->ire_marks & IRE_MARK_CONDEMNED) ||
-			    ire->ire_zoneid != zoneid)
+			    (ire->ire_zoneid != zoneid &&
+			    ire->ire_zoneid != ALL_ZONES))
 				continue;
 			switch (ire->ire_type) {
 			case IRE_LOOPBACK:
@@ -2452,7 +2496,7 @@
  * if this ire is used.
  */
 ill_t *
-ire_to_ill(ire_t *ire)
+ire_to_ill(const ire_t *ire)
 {
 	ill_t *ill = NULL;
 
@@ -2501,19 +2545,19 @@
 
 /* Arrange to call the specified function for every IRE in the world. */
 void
-ire_walk(pfv_t func, char *arg)
+ire_walk(pfv_t func, void *arg)
 {
 	ire_walk_ipvers(func, arg, 0, ALL_ZONES);
 }
 
 void
-ire_walk_v4(pfv_t func, char *arg, zoneid_t zoneid)
+ire_walk_v4(pfv_t func, void *arg, zoneid_t zoneid)
 {
 	ire_walk_ipvers(func, arg, IPV4_VERSION, zoneid);
 }
 
 void
-ire_walk_v6(pfv_t func, char *arg, zoneid_t zoneid)
+ire_walk_v6(pfv_t func, void *arg, zoneid_t zoneid)
 {
 	ire_walk_ipvers(func, arg, IPV6_VERSION, zoneid);
 }
@@ -2522,7 +2566,7 @@
  * Walk a particular version. version == 0 means both v4 and v6.
  */
 static void
-ire_walk_ipvers(pfv_t func, char *arg, uchar_t vers, zoneid_t zoneid)
+ire_walk_ipvers(pfv_t func, void *arg, uchar_t vers, zoneid_t zoneid)
 {
 	if (vers != IPV6_VERSION) {
 		ire_walk_ill_tables(0, 0, func, arg, IP_MASK_TABLE_SIZE,
@@ -2541,14 +2585,14 @@
  * function for every IRE that matches the ill.
  */
 void
-ire_walk_ill(uint_t match_flags, uint_t ire_type, pfv_t func, char *arg,
+ire_walk_ill(uint_t match_flags, uint_t ire_type, pfv_t func, void *arg,
     ill_t *ill)
 {
 	ire_walk_ill_ipvers(match_flags, ire_type, func, arg, 0, ill);
 }
 
 void
-ire_walk_ill_v4(uint_t match_flags, uint_t ire_type, pfv_t func, char *arg,
+ire_walk_ill_v4(uint_t match_flags, uint_t ire_type, pfv_t func, void *arg,
     ill_t *ill)
 {
 	ire_walk_ill_ipvers(match_flags, ire_type, func, arg, IPV4_VERSION,
@@ -2556,7 +2600,7 @@
 }
 
 void
-ire_walk_ill_v6(uint_t match_flags, uint_t ire_type, pfv_t func, char *arg,
+ire_walk_ill_v6(uint_t match_flags, uint_t ire_type, pfv_t func, void *arg,
     ill_t *ill)
 {
 	ire_walk_ill_ipvers(match_flags, ire_type, func, arg, IPV6_VERSION,
@@ -2568,7 +2612,7 @@
  */
 static void
 ire_walk_ill_ipvers(uint_t match_flags, uint_t ire_type, pfv_t func,
-    char *arg, uchar_t vers, ill_t *ill)
+    void *arg, uchar_t vers, ill_t *ill)
 {
 	if (vers != IPV6_VERSION) {
 		ire_walk_ill_tables(match_flags, ire_type, func, arg,
@@ -2639,7 +2683,7 @@
 		 * routes that can be matched during lookup are also matched
 		 * here.
 		 */
-		if (zoneid != ire->ire_zoneid) {
+		if (zoneid != ire->ire_zoneid && ire->ire_zoneid != ALL_ZONES) {
 			/*
 			 * Note, IRE_INTERFACE can have the stq as NULL. For
 			 * example, if the default multicast route is tied to
@@ -2693,7 +2737,7 @@
 			}
 			if (ire->ire_ipversion == IPV4_VERSION) {
 				rire = ire_route_lookup(ire->ire_gateway_addr,
-				    0, 0, 0, ire->ire_ipif, NULL, zoneid,
+				    0, 0, 0, ire->ire_ipif, NULL, zoneid, NULL,
 				    ire_match_flags);
 			} else {
 				ASSERT(ire->ire_ipversion == IPV6_VERSION);
@@ -2702,7 +2746,7 @@
 				mutex_exit(&ire->ire_lock);
 				rire = ire_route_lookup_v6(&gw_addr_v6,
 				    NULL, NULL, 0, ire->ire_ipif, NULL, zoneid,
-				    ire_match_flags);
+				    NULL, ire_match_flags);
 			}
 			if (rire == NULL) {
 				return (B_FALSE);
@@ -2731,7 +2775,7 @@
  */
 static void
 ire_walk_ill_tables(uint_t match_flags, uint_t ire_type, pfv_t func,
-    char *arg, size_t ftbl_sz, size_t htbl_sz, irb_t **ipftbl,
+    void *arg, size_t ftbl_sz, size_t htbl_sz, irb_t **ipftbl,
     size_t ctbl_sz, irb_t *ipctbl, ill_t *ill, zoneid_t zoneid)
 {
 	irb_t	*irb_ptr;
@@ -2812,7 +2856,7 @@
  * down/deleted or the 'ipv4_ire_srcif_status' report is printed.
  */
 void
-ire_walk_srcif_table_v4(pfv_t func, char *arg)
+ire_walk_srcif_table_v4(pfv_t func, void *arg)
 {
 	irb_t   *irb;
 	ire_t   *ire;
@@ -3154,7 +3198,7 @@
 		    &ipif->ipif_v6src_addr)) ||
 		    (!ipif->ipif_isv6 &&
 		    ire->ire_src_addr != ipif->ipif_src_addr) ||
-		    (ire->ire_zoneid != ipif->ipif_zoneid)) {
+		    ire->ire_zoneid != ipif->ipif_zoneid) {
 
 			if (ipif != NULL)
 				ipif_refrele(ipif);
@@ -3484,7 +3528,7 @@
 			continue;
 		if (ire_match_args(ire1, ire->ire_addr, ire->ire_mask,
 		    ire->ire_gateway_addr, ire->ire_type, ire->ire_ipif,
-		    ire->ire_zoneid, 0, flags)) {
+		    ire->ire_zoneid, 0, NULL, flags)) {
 			/*
 			 * Return the old ire after doing a REFHOLD.
 			 * As most of the callers continue to use the IRE
@@ -3683,7 +3727,7 @@
 		if (ire->ire_mask == IP_HOST_MASK) {
 			ire_t *lire;
 			lire = ire_ctable_lookup(ire->ire_addr, NULL, IRE_CACHE,
-			    NULL, ALL_ZONES, MATCH_IRE_TYPE);
+			    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
 			if (lire != NULL) {
 				ire_refrele(lire);
 				ire_flush_cache_v4(ire, IRE_FLUSH_ADD);
@@ -4187,6 +4231,10 @@
 		ire->ire_in_ill = NULL;
 	}
 
+	if (ire->ire_gw_secattr != NULL) {
+		ire_gw_secattr_free(ire->ire_gw_secattr);
+		ire->ire_gw_secattr = NULL;
+	}
 #ifdef IRE_DEBUG
 	ire_trace_inactive(ire);
 #endif
@@ -4368,7 +4416,8 @@
  */
 static boolean_t
 ire_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway,
-    int type, ipif_t *ipif, zoneid_t zoneid, uint32_t ihandle, int match_flags)
+    int type, const ipif_t *ipif, zoneid_t zoneid, uint32_t ihandle,
+    const ts_label_t *tsl, int match_flags)
 {
 	ill_t *ire_ill = NULL, *dst_ill;
 	ill_t *ipif_ill = NULL;
@@ -4405,7 +4454,8 @@
 	    (ire->ire_marks & IRE_MARK_PRIVATE_ADDR))
 		return (B_FALSE);
 
-	if (zoneid != ALL_ZONES && zoneid != ire->ire_zoneid) {
+	if (zoneid != ALL_ZONES && zoneid != ire->ire_zoneid &&
+	    ire->ire_zoneid != ALL_ZONES) {
 		/*
 		 * If MATCH_IRE_ZONEONLY has been set and the supplied zoneid is
 		 * valid and does not match that of ire_zoneid, a failure to
@@ -4472,7 +4522,8 @@
 			    tipif != NULL; tipif = tipif->ipif_next) {
 				if (IPIF_CAN_LOOKUP(tipif) &&
 				    (tipif->ipif_flags & IPIF_UP) &&
-				    (tipif->ipif_zoneid == zoneid))
+				    (tipif->ipif_zoneid == zoneid ||
+				    tipif->ipif_zoneid == ALL_ZONES))
 					break;
 			}
 			mutex_exit(&ire->ire_ipif->ipif_ill->ill_lock);
@@ -4520,7 +4571,10 @@
 	    ((!(match_flags & MATCH_IRE_ILL_GROUP)) ||
 		(ire_ill == ipif_ill) ||
 		(ire_ill_group != NULL &&
-		ire_ill_group == ipif_ill_group))) {
+		ire_ill_group == ipif_ill_group)) &&
+	    ((!(match_flags & MATCH_IRE_SECATTR)) ||
+		(!is_system_labeled()) ||
+		(tsol_ire_match_gwattr(ire, tsl) == 0))) {
 		/* We found the matched IRE */
 		return (B_TRUE);
 	}
@@ -4533,7 +4587,8 @@
  */
 ire_t *
 ire_route_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway,
-    int type, ipif_t *ipif, ire_t **pire, zoneid_t zoneid, int flags)
+    int type, const ipif_t *ipif, ire_t **pire, zoneid_t zoneid,
+    const ts_label_t *tsl, int flags)
 {
 	ire_t *ire = NULL;
 
@@ -4555,13 +4610,13 @@
 	 */
 	if ((flags & MATCH_IRE_TYPE) == 0 || (type & IRE_CACHETABLE) != 0) {
 		ire = ire_ctable_lookup(addr, gateway, type, ipif, zoneid,
-		    flags);
+		    tsl, flags);
 		if (ire != NULL)
 			return (ire);
 	}
 	if ((flags & MATCH_IRE_TYPE) == 0 || (type & IRE_FORWARDTABLE) != 0) {
 		ire = ire_ftable_lookup(addr, mask, gateway, type, ipif, pire,
-		    zoneid, 0, flags);
+		    zoneid, 0, tsl, flags);
 	}
 	return (ire);
 }
@@ -4599,8 +4654,8 @@
  */
 ire_t *
 ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway,
-    int type, ipif_t *ipif, ire_t **pire, zoneid_t zoneid, uint32_t ihandle,
-    int flags)
+    int type, const ipif_t *ipif, ire_t **pire, zoneid_t zoneid,
+    uint32_t ihandle, const ts_label_t *tsl, int flags)
 {
 	irb_t *irb_ptr;
 	ire_t *ire = NULL;
@@ -4644,7 +4699,7 @@
 			if (ire->ire_marks & IRE_MARK_CONDEMNED)
 				continue;
 			if (ire_match_args(ire, addr, mask, gateway, type, ipif,
-			    zoneid, ihandle, flags))
+			    zoneid, ihandle, tsl, flags))
 				goto found_ire;
 		}
 		rw_exit(&irb_ptr->irb_lock);
@@ -4670,7 +4725,7 @@
 					continue;
 				if (ire_match_args(ire, addr, ire->ire_mask,
 				    gateway, type, ipif, zoneid, ihandle,
-				    flags))
+				    tsl, flags))
 					goto found_ire;
 			}
 			rw_exit(&irb_ptr->irb_lock);
@@ -4701,7 +4756,7 @@
 					continue;
 				if (ire_match_args(ire, addr, (ipaddr_t)0,
 				    gateway, type, ipif, zoneid, ihandle,
-				    flags))
+				    tsl, flags))
 					goto found_ire;
 			}
 			rw_exit(&irb_ptr->irb_lock);
@@ -4780,7 +4835,7 @@
 		    ire = ire_get_next_default_ire(ire, ire_origin)) {
 
 			if (ire_match_args(ire, addr, (ipaddr_t)0,
-			    gateway, type, ipif, zoneid, ihandle, flags)) {
+			    gateway, type, ipif, zoneid, ihandle, tsl, flags)) {
 				int match_flags = 0;
 				ire_t *rire;
 
@@ -4804,7 +4859,7 @@
 					match_flags |= MATCH_IRE_ILL_GROUP;
 				}
 				rire = ire_route_lookup(ire->ire_gateway_addr,
-				    0, 0, 0, ire->ire_ipif, NULL, zoneid,
+				    0, 0, 0, ire->ire_ipif, NULL, zoneid, tsl,
 				    match_flags);
 				if (rire != NULL) {
 					ire_refrele(rire);
@@ -4830,7 +4885,8 @@
 				continue;
 
 			if (ire_match_args(ire, addr, (ipaddr_t)0,
-			    gateway, type, ipif, zoneid, ihandle, flags)) {
+			    gateway, type, ipif, zoneid, ihandle, tsl,
+			    flags)) {
 				IRE_REFHOLD(ire);
 				IRB_REFRELE(irb_ptr);
 				goto found_ire_held;
@@ -4862,7 +4918,7 @@
 	 * of lookup is done.
 	 */
 	if (flags & MATCH_IRE_RECURSIVE) {
-		ipif_t	*gw_ipif;
+		const ipif_t *gw_ipif;
 		int match_flags = MATCH_IRE_DSTONLY;
 		ire_t *save_ire;
 
@@ -4893,7 +4949,7 @@
 			match_flags |= MATCH_IRE_ILL_GROUP;
 
 		ire = ire_route_lookup(ire->ire_gateway_addr, 0, 0, 0,
-		    ire->ire_ipif, NULL, zoneid, match_flags);
+		    ire->ire_ipif, NULL, zoneid, tsl, match_flags);
 		if (ire == NULL) {
 			/*
 			 * Do not release the parent ire if MATCH_IRE_PARENT
@@ -4932,7 +4988,7 @@
 		ire_refrele(ire);
 		ire = ire_route_lookup(gw_addr, 0, 0,
 		    (IRE_CACHETABLE | IRE_INTERFACE), gw_ipif, NULL, zoneid,
-		    match_flags);
+		    tsl, match_flags);
 		if (ire == NULL) {
 			/*
 			 * Do not release the parent ire if MATCH_IRE_PARENT
@@ -4968,14 +5024,43 @@
 }
 
 /*
+ * Delete the IRE cache for the gateway and all IRE caches whose
+ * ire_gateway_addr points to this gateway, and allow them to
+ * be created on demand by ip_newroute.
+ */
+void
+ire_clookup_delete_cache_gw(ipaddr_t addr, zoneid_t zoneid)
+{
+	irb_t *irb;
+	ire_t *ire;
+
+	irb = &ip_cache_table[IRE_ADDR_HASH(addr, ip_cache_table_size)];
+	IRB_REFHOLD(irb);
+	for (ire = irb->irb_ire; ire != NULL; ire = ire->ire_next) {
+		if (ire->ire_marks & IRE_MARK_CONDEMNED)
+			continue;
+
+		ASSERT(ire->ire_mask == IP_HOST_MASK);
+		ASSERT(ire->ire_type != IRE_MIPRTUN && ire->ire_in_ill == NULL);
+		if (ire_match_args(ire, addr, ire->ire_mask, 0, IRE_CACHE,
+		    NULL, zoneid, 0, NULL, MATCH_IRE_TYPE)) {
+			ire_delete(ire);
+		}
+	}
+	IRB_REFRELE(irb);
+
+	ire_walk_v4(ire_delete_cache_gw, &addr, zoneid);
+}
+
+/*
  * Looks up cache table for a route.
  * specific lookup can be indicated by
  * passing the MATCH_* flags and the
  * necessary parameters.
  */
 ire_t *
-ire_ctable_lookup(ipaddr_t addr, ipaddr_t gateway, int type, ipif_t *ipif,
-    zoneid_t zoneid, int flags)
+ire_ctable_lookup(ipaddr_t addr, ipaddr_t gateway, int type, const ipif_t *ipif,
+    zoneid_t zoneid, const ts_label_t *tsl, int flags)
 {
 	irb_t *irb_ptr;
 	ire_t *ire;
@@ -4996,7 +5081,7 @@
 		ASSERT(ire->ire_mask == IP_HOST_MASK);
 		ASSERT(ire->ire_type != IRE_MIPRTUN && ire->ire_in_ill == NULL);
 		if (ire_match_args(ire, addr, ire->ire_mask, gateway, type,
-		    ipif, zoneid, 0, flags)) {
+		    ipif, zoneid, 0, tsl, flags)) {
 			IRE_REFHOLD(ire);
 			rw_exit(&irb_ptr->irb_lock);
 			return (ire);
@@ -5012,7 +5097,7 @@
  * to the hidden ones.
  */
 ire_t *
-ire_cache_lookup(ipaddr_t addr, zoneid_t zoneid)
+ire_cache_lookup(ipaddr_t addr, zoneid_t zoneid, const ts_label_t *tsl)
 {
 	irb_t *irb_ptr;
 	ire_t *ire;
@@ -5025,7 +5110,19 @@
 			continue;
 		}
 		if (ire->ire_addr == addr) {
+			/*
+			 * Finally, check if the security policy has any
+			 * restriction on using this route for the specified
+			 * message.
+			 */
+			if (tsl != NULL &&
+			    ire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(ire, tsl) != 0) {
+				continue;
+			}
+
 			if (zoneid == ALL_ZONES || ire->ire_zoneid == zoneid ||
+			    ire->ire_zoneid == ALL_ZONES ||
 			    ire->ire_type == IRE_LOCAL) {
 				IRE_REFHOLD(ire);
 				rw_exit(&irb_ptr->irb_lock);
@@ -5075,7 +5172,7 @@
 	 */
 	ire = ire_ftable_lookup(cire->ire_addr, cire->ire_cmask, 0,
 	    IRE_INTERFACE, pire->ire_ipif, NULL, ALL_ZONES, cire->ire_ihandle,
-	    match_flags);
+	    NULL, match_flags);
 	if (ire != NULL)
 		return (ire);
 	/*
@@ -5106,7 +5203,7 @@
 	if (pire->ire_ipif != NULL)
 		match_flags |= MATCH_IRE_ILL_GROUP;
 	ire = ire_ftable_lookup(pire->ire_gateway_addr, 0, 0, IRE_OFFSUBNET,
-	    pire->ire_ipif, NULL, ALL_ZONES, 0, match_flags);
+	    pire->ire_ipif, NULL, ALL_ZONES, 0, NULL, match_flags);
 	if (ire == NULL)
 		return (NULL);
 	/*
@@ -5119,7 +5216,7 @@
 
 	match_flags |= MATCH_IRE_IHANDLE;
 	ire = ire_ftable_lookup(gw_addr, 0, 0, IRE_INTERFACE,
-	    gw_ipif, NULL, ALL_ZONES, cire->ire_ihandle, match_flags);
+	    gw_ipif, NULL, ALL_ZONES, cire->ire_ihandle, NULL, match_flags);
 	return (ire);
 }
 
@@ -5154,7 +5251,7 @@
 	 */
 	ire = ire_ftable_lookup(cire->ire_addr, cire->ire_cmask, 0,
 	    IRE_INTERFACE, NULL, NULL, ALL_ZONES, cire->ire_ihandle,
-	    match_flags);
+	    NULL, match_flags);
 	if (ire != NULL)
 		return (ire);
 	/*
@@ -5249,23 +5346,23 @@
  * the ipif, this routine might return NULL.
  */
 ire_t *
-ipif_to_ire(ipif_t *ipif)
+ipif_to_ire(const ipif_t *ipif)
 {
 	ire_t	*ire;
 
 	ASSERT(!ipif->ipif_isv6);
 	if (ipif->ipif_ire_type == IRE_LOOPBACK) {
 		ire = ire_ctable_lookup(ipif->ipif_lcl_addr, 0, IRE_LOOPBACK,
-		    ipif, ALL_ZONES, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
+		    ipif, ALL_ZONES, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF));
 	} else if (ipif->ipif_flags & IPIF_POINTOPOINT) {
 		/* In this case we need to lookup destination address. */
 		ire = ire_ftable_lookup(ipif->ipif_pp_dst_addr, IP_HOST_MASK, 0,
-		    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
+		    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0, NULL,
 		    (MATCH_IRE_TYPE | MATCH_IRE_IPIF | MATCH_IRE_MASK));
 	} else {
 		ire = ire_ftable_lookup(ipif->ipif_subnet,
 		    ipif->ipif_net_mask, 0, IRE_INTERFACE, ipif, NULL,
-		    ALL_ZONES, 0, (MATCH_IRE_TYPE | MATCH_IRE_IPIF |
+		    ALL_ZONES, 0, NULL, (MATCH_IRE_TYPE | MATCH_IRE_IPIF |
 		    MATCH_IRE_MASK));
 	}
 	return (ire);
@@ -5730,7 +5827,7 @@
 		if (ire->ire_marks & IRE_MARK_CONDEMNED)
 			continue;
 		if (ire_match_args(ire, dst_addr, ire->ire_mask, 0,
-		    ire_type, ipif, ire->ire_zoneid, 0, flags)) {
+		    ire_type, ipif, ire->ire_zoneid, 0, NULL, flags)) {
 			IRE_REFHOLD(ire);
 			rw_exit(&irb_ptr->irb_lock);
 			return (ire);
@@ -5852,7 +5949,8 @@
 			continue;
 		/* Has anyone inserted route in the meanwhile ? */
 		if (ire_match_args(ire1, ire->ire_addr, ire->ire_mask, 0,
-		    ire->ire_type, ire->ire_ipif, ire->ire_zoneid, 0, flags)) {
+		    ire->ire_type, ire->ire_ipif, ire->ire_zoneid, 0, NULL,
+		    flags)) {
 			ip1dbg(("ire_add_srcif_v4 : Duplicate entry exists\n"));
 			IRE_REFHOLD(ire1);
 			ire_atomic_end(irb_ptr, ire);
@@ -5996,7 +6094,7 @@
  * This only works in the global zone.
  */
 boolean_t
-ire_multirt_need_resolve(ipaddr_t dst)
+ire_multirt_need_resolve(ipaddr_t dst, const ts_label_t *tsl)
 {
 	ire_t	*first_fire;
 	ire_t	*first_cire;
@@ -6009,7 +6107,8 @@
 
 	/* Retrieve the first IRE_HOST that matches the destination */
 	first_fire = ire_ftable_lookup(dst, IP_HOST_MASK, 0, IRE_HOST, NULL,
-	    NULL, ALL_ZONES, 0, MATCH_IRE_MASK | MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, 0, tsl,
+	    MATCH_IRE_MASK | MATCH_IRE_TYPE | MATCH_IRE_SECATTR);
 
 	/* No route at all */
 	if (first_fire == NULL) {
@@ -6020,7 +6119,7 @@
 	ASSERT(firb != NULL);
 
 	/* Retrieve the first IRE_CACHE ire for that destination. */
-	first_cire = ire_cache_lookup(dst, GLOBAL_ZONEID);
+	first_cire = ire_cache_lookup(dst, GLOBAL_ZONEID, tsl);
 
 	/* No resolved route. */
 	if (first_cire == NULL) {
@@ -6065,7 +6164,7 @@
 	/* At least one route is unresolved; search for a resolvable route. */
 	if (unres_cnt > 0)
 		resolvable = ire_multirt_lookup(&first_cire, &first_fire,
-		    MULTIRT_USESTAMP | MULTIRT_CACHEGW);
+		    MULTIRT_USESTAMP | MULTIRT_CACHEGW, tsl);
 
 	if (first_fire != NULL)
 		ire_refrele(first_fire);
@@ -6128,7 +6227,8 @@
  * This only works in the global zone.
  */
 boolean_t
-ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags)
+ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags,
+    const ts_label_t *tsl)
 {
 	clock_t	delta;
 	ire_t	*best_fire = NULL;
@@ -6170,7 +6270,7 @@
 	 * if we don't find one, no route for that dest is
 	 * resolved yet.
 	 */
-	first_cire = ire_cache_lookup(dst, GLOBAL_ZONEID);
+	first_cire = ire_cache_lookup(dst, GLOBAL_ZONEID, tsl);
 	if (first_cire != NULL) {
 		cirb = first_cire->ire_bucket;
 	}
@@ -6196,6 +6296,11 @@
 			if (fire->ire_addr != dst)
 				continue;
 
+			if (fire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(fire, tsl) != 0) {
+				continue;
+			}
+
 			gw = fire->ire_gateway_addr;
 
 			ip2dbg(("ire_multirt_lookup: fire %p, "
@@ -6224,6 +6329,13 @@
 					    (IRE_MARK_CONDEMNED |
 						IRE_MARK_HIDDEN))
 						continue;
+
+					if (cire->ire_gw_secattr != NULL &&
+					    tsol_ire_match_gwattr(cire,
+					    tsl) != 0) {
+						continue;
+					}
+
 					/*
 					 * Check if the IRE_CACHE's gateway
 					 * matches the IRE_HOST's gateway.
@@ -6252,7 +6364,8 @@
 			 * for the gateway?
 			 */
 			gw_ire = ire_route_lookup(gw, 0, 0, 0, NULL, NULL,
-			    ALL_ZONES, MATCH_IRE_RECURSIVE);
+			    ALL_ZONES, tsl,
+			    MATCH_IRE_RECURSIVE | MATCH_IRE_SECATTR);
 
 			ip2dbg(("ire_multirt_lookup: looked up gw_ire %p\n",
 			    (void *)gw_ire));
@@ -6377,13 +6490,19 @@
 			if (fire->ire_addr != dst)
 				continue;
 
+			if (fire->ire_gw_secattr != NULL &&
+			    tsol_ire_match_gwattr(fire, tsl) != 0) {
+				continue;
+			}
+
 			already_resolved = B_FALSE;
 
 			gw = fire->ire_gateway_addr;
 
 			gw_ire = ire_ftable_lookup(gw, 0, 0, IRE_INTERFACE,
-			    NULL, NULL, ALL_ZONES, 0,
-			    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE);
+			    NULL, NULL, ALL_ZONES, 0, tsl,
+			    MATCH_IRE_RECURSIVE | MATCH_IRE_TYPE |
+			    MATCH_IRE_SECATTR);
 
 			/* No resolver for the gateway; we skip this ire. */
 			if (gw_ire == NULL) {
@@ -6410,6 +6529,12 @@
 						IRE_MARK_HIDDEN))
 						continue;
 
+					if (cire->ire_gw_secattr != NULL &&
+					    tsol_ire_match_gwattr(cire,
+					    tsl) != 0) {
+						continue;
+					}
+
 					/*
 					 * Cache entries are linked to the
 					 * parent routes using the parent handle
@@ -6535,7 +6660,7 @@
 	ASSERT(CLASSD(group));
 
 	ire = ire_ftable_lookup(group, 0, 0, 0, NULL, NULL, ALL_ZONES, 0,
-	    MATCH_IRE_DEFAULT);
+	    NULL, MATCH_IRE_DEFAULT);
 
 	if (ire == NULL)
 		return (NULL);
@@ -6547,7 +6672,8 @@
 	ire_refrele(ire);
 	for (ire = irb->irb_ire; ire != NULL; ire = ire->ire_next) {
 		if (ire->ire_addr != group ||
-		    ipif->ipif_zoneid != ire->ire_zoneid) {
+		    (ipif->ipif_zoneid != ire->ire_zoneid &&
+		    ire->ire_zoneid != ALL_ZONES)) {
 			continue;
 		}
 
@@ -6557,7 +6683,7 @@
 		case IRE_HOST:
 			gw_addr = ire->ire_gateway_addr;
 			gw_ire = ire_ftable_lookup(gw_addr, 0, 0, IRE_INTERFACE,
-			    ipif, NULL, ALL_ZONES, 0, match_flags);
+			    ipif, NULL, ALL_ZONES, 0, NULL, match_flags);
 
 			if (gw_ire != NULL) {
 				if (save_ire != NULL) {
@@ -6625,14 +6751,14 @@
 		dir = ire_route_lookup(
 		    ((struct sockaddr_in *)target)->sin_addr.s_addr,
 		    0xffffffff,
-		    0, 0, NULL, NULL, ALL_ZONES,
+		    0, 0, NULL, NULL, ALL_ZONES, NULL,
 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE);
 		break;
 	case AF_INET6:
 		dir = ire_route_lookup_v6(
 		    &((struct sockaddr_in6 *)target)->sin6_addr,
 		    NULL,
-		    0, 0, NULL, NULL, ALL_ZONES,
+		    0, 0, NULL, NULL, ALL_ZONES, NULL,
 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE);
 		if ((dir != NULL) && (dir->ire_nce == NULL)) {
 			ire_refrele(dir);
@@ -6756,14 +6882,14 @@
 		dir = ire_route_lookup(
 			((struct sockaddr_in *)target)->sin_addr.s_addr,
 			0xffffffff,
-			0, 0, ill->ill_ipif, NULL, ALL_ZONES,
+			0, 0, ill->ill_ipif, NULL, ALL_ZONES, NULL,
 			MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|
 			MATCH_IRE_RECURSIVE|MATCH_IRE_IPIF);
 		break;
 	case AF_INET6:
 		dir = ire_route_lookup_v6(
 			&((struct sockaddr_in6 *)target)->sin6_addr, NULL,
-			0, 0, ill->ill_ipif, NULL, ALL_ZONES,
+			0, 0, ill->ill_ipif, NULL, ALL_ZONES, NULL,
 			MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|
 			MATCH_IRE_RECURSIVE|MATCH_IRE_IPIF);
 		if ((dir != NULL) && (dir->ire_nce == NULL)) {
--- a/usr/src/uts/common/inet/ip/ip_mroute.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_mroute.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.
+ * Copyright 2006 Sun Microsystems, Inc.
  * All rights reserved.  Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -48,7 +47,6 @@
 
 #include <sys/types.h>
 #include <sys/stream.h>
-#include <sys/dlpi.h>
 #include <sys/stropts.h>
 #include <sys/strlog.h>
 #include <sys/systm.h>
@@ -58,21 +56,16 @@
 
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
 #include <sys/vtrace.h>
 #include <sys/debug.h>
 #include <net/if.h>
-#include <net/if_arp.h>
 #include <sys/sockio.h>
-#include <net/route.h>
 #include <netinet/in.h>
 #include <net/if_dl.h>
 
 #include <inet/common.h>
 #include <inet/mi.h>
 #include <inet/nd.h>
-#include <inet/arp.h>
 #include <inet/mib2.h>
 #include <netinet/ip6.h>
 #include <inet/ip.h>
@@ -2992,7 +2985,7 @@
 			}
 			mp_loop = copymsg(mp);
 			ire = ire_ctable_lookup(~0, 0, IRE_BROADCAST, NULL,
-			    ALL_ZONES, MATCH_IRE_TYPE);
+			    ALL_ZONES, NULL, MATCH_IRE_TYPE);
 
 			if (mp_loop != NULL && ire != NULL) {
 				IP_RPUT_LOCAL(ipif->ipif_rq, mp_loop,
--- a/usr/src/uts/common/inet/ip/ip_multi.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_multi.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -32,18 +31,14 @@
 #include <sys/dlpi.h>
 #include <sys/stropts.h>
 #include <sys/strsun.h>
-#include <sys/strlog.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
 #include <sys/zone.h>
 
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
+#include <sys/sockio.h>
 #include <net/if.h>
-#include <net/if_arp.h>
-#include <sys/sockio.h>
 #include <sys/systm.h>
 #include <net/route.h>
 #include <netinet/in.h>
@@ -58,7 +53,6 @@
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_if.h>
-#include <inet/ip_ire.h>
 #include <inet/ip_ndp.h>
 #include <inet/ip_multi.h>
 #include <inet/ipclassifier.h>
@@ -67,8 +61,6 @@
 #include <inet/ip_listutils.h>
 #include <inet/udp_impl.h>
 
-#include <netinet/igmp.h>
-
 /* igmpv3/mldv2 source filter manipulation */
 static void	ilm_bld_flists(conn_t *conn, void *arg);
 static void	ilm_gen_filter(ilm_t *ilm, mcast_record_t *fmode,
@@ -1706,6 +1698,7 @@
 	ilm->ilm_zoneid = zoneid;
 	ilm->ilm_timer = INFINITY;
 	ilm->ilm_rtx.rtx_timer = INFINITY;
+
 	/*
 	 * IPv4 Multicast groups are joined using ipif.
 	 * IPv6 Multicast groups are joined using ill.
--- a/usr/src/uts/common/inet/ip/ip_ndp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_ndp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,11 +30,7 @@
 #include <sys/stropts.h>
 #include <sys/sysmacros.h>
 #include <sys/errno.h>
-#include <sys/strlog.h>
 #include <sys/dlpi.h>
-#include <sys/sockio.h>
-#include <sys/tiuser.h>
-#include <sys/tihdr.h>
 #include <sys/socket.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
@@ -45,12 +40,9 @@
 #include <sys/zone.h>
 
 #include <net/if.h>
-#include <net/if_types.h>
 #include <net/if_dl.h>
 #include <net/route.h>
-#include <sys/sockio.h>
 #include <netinet/in.h>
-#include <netinet/in_systm.h>
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 
@@ -58,9 +50,7 @@
 #include <inet/mi.h>
 #include <inet/mib2.h>
 #include <inet/nd.h>
-#include <inet/arp.h>
 #include <inet/ip.h>
-#include <inet/ip_multi.h>
 #include <inet/ip_if.h>
 #include <inet/ip_ire.h>
 #include <inet/ip_rts.h>
@@ -762,7 +752,7 @@
 			 */
 			ire = ire_ftable_lookup_v6(&ipv6_all_zeros,
 			    &ipv6_all_zeros, &nce->nce_addr, IRE_DEFAULT,
-			    nce->nce_ill->ill_ipif, NULL, ALL_ZONES, 0,
+			    nce->nce_ill->ill_ipif, NULL, ALL_ZONES, 0, NULL,
 			    MATCH_IRE_ILL | MATCH_IRE_TYPE | MATCH_IRE_GW |
 			    MATCH_IRE_DEFAULT);
 			if (ire != NULL) {
@@ -781,7 +771,7 @@
  * walking the hash list.
  */
 void
-ndp_walk_impl(ill_t *ill, pfi_t pfi, uchar_t *arg1, boolean_t trace)
+ndp_walk_impl(ill_t *ill, pfi_t pfi, void *arg1, boolean_t trace)
 {
 
 	nce_t	*nce;
@@ -852,7 +842,7 @@
 }
 
 void
-ndp_walk(ill_t *ill, pfi_t pfi, uchar_t *arg1)
+ndp_walk(ill_t *ill, pfi_t pfi, void *arg1)
 {
 	ndp_walk_impl(ill, pfi, arg1, B_TRUE);
 }
@@ -869,6 +859,7 @@
 	mblk_t		*first_mp;
 	ipsec_out_t	*io;
 
+	ASSERT(zoneid != ALL_ZONES);
 	if (mp->b_datap->db_type == M_CTL) {
 		io = (ipsec_out_t *)mp->b_rptr;
 		ASSERT(io->ipsec_out_type == IPSEC_OUT);
--- a/usr/src/uts/common/inet/ip/ip_opt_data.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_opt_data.c	Fri Mar 24 12:29:20 2006 -0800
@@ -37,7 +37,6 @@
 #include <inet/ip.h>
 
 #include <netinet/in.h>
-#include <netinet/tcp.h>
 #include <netinet/ip_mroute.h>
 #include <inet/optcom.h>
 
@@ -63,6 +62,9 @@
 { SO_BROADCAST,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
 { SO_PROTOTYPE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
+{ SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0
+	},
 
 { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
 	(OP_PASSNEXT|OP_VARLEN|OP_NODEFAULT), 40, -1 /* not initialized */ },
--- a/usr/src/uts/common/inet/ip/ip_rts.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip_rts.c	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,8 +47,6 @@
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <sys/stropts.h>
-#include <sys/strlog.h>
-#include <sys/dlpi.h>
 #include <sys/ddi.h>
 #include <sys/cmn_err.h>
 #include <sys/debug.h>
@@ -58,8 +56,6 @@
 #include <sys/systm.h>
 #include <sys/param.h>
 #include <sys/socket.h>
-#define	_SUN_TPI_VERSION	2
-#include <sys/tihdr.h>
 #include <sys/strsun.h>
 #include <net/if.h>
 #include <net/route.h>
@@ -68,28 +64,30 @@
 #include <netinet/ip6.h>
 
 #include <inet/common.h>
-#include <inet/mi.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_if.h>
 #include <inet/ip_ire.h>
 #include <inet/ip_rts.h>
-#include <inet/ip_multi.h>
 
 #include <inet/ipclassifier.h>
 
-#define	RTS_MSG_SIZE(type, rtm_addrs, af) \
-	(rts_data_msg_size(rtm_addrs, af) + rts_header_msg_size(type))
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
+
+#define	RTS_MSG_SIZE(type, rtm_addrs, af, sacnt) \
+	(rts_data_msg_size(rtm_addrs, af, sacnt) + rts_header_msg_size(type))
 
 static size_t	rts_copyfromsockaddr(struct sockaddr *sa, in6_addr_t *addrp);
 static void	rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst,
     ipaddr_t mask, ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr,
-    ipaddr_t author, ipif_t *ipif, mblk_t *mp);
+    ipaddr_t author, const ipif_t *ipif, mblk_t *mp, uint_t, const tsol_gc_t *);
 static int	rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp,
     in6_addr_t *gw_addrp, in6_addr_t *net_maskp, in6_addr_t *authorp,
     in6_addr_t *if_addrp, in6_addr_t *src_addrp, ushort_t *indexp,
-    ushort_t *src_indexp, sa_family_t *afp);
-static void	rts_getifdata(if_data_t *if_data, ipif_t *ipif);
+    ushort_t *src_indexp, sa_family_t *afp, tsol_rtsecattr_t *rtsecattr,
+    int *error);
+static void	rts_getifdata(if_data_t *if_data, const ipif_t *ipif);
 static int	rts_getmetrics(ire_t *ire, rt_metrics_t *metrics);
 static mblk_t	*rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire,
     sa_family_t af);
@@ -187,15 +185,16 @@
 	switch (ire->ire_ipversion) {
 	case IPV4_VERSION:
 		af = AF_INET;
-		mp = rts_alloc_msg(type, rtm_addrs, af);
+		mp = rts_alloc_msg(type, rtm_addrs, af, 0);
 		if (mp == NULL)
 			return;
 		rts_fill_msg(type, rtm_addrs, ire->ire_addr, ire->ire_mask,
-		    ire->ire_gateway_addr, ire->ire_src_addr, 0, 0, NULL, mp);
+		    ire->ire_gateway_addr, ire->ire_src_addr, 0, 0, NULL, mp,
+		    0, NULL);
 		break;
 	case IPV6_VERSION:
 		af = AF_INET6;
-		mp = rts_alloc_msg(type, rtm_addrs, af);
+		mp = rts_alloc_msg(type, rtm_addrs, af, 0);
 		if (mp == NULL)
 			return;
 		mutex_enter(&ire->ire_lock);
@@ -204,7 +203,7 @@
 		rts_fill_msg_v6(type, rtm_addrs, &ire->ire_addr_v6,
 		    &ire->ire_mask_v6, &gw_addr_v6,
 		    &ire->ire_src_addr_v6, &ipv6_all_zeros, &ipv6_all_zeros,
-		    NULL, mp);
+		    NULL, mp, 0, NULL);
 		break;
 	}
 	rtm = (rt_msghdr_t *)mp->b_rptr;
@@ -272,6 +271,12 @@
 	ipif_t		*tmp_ipif = NULL;
 	IOCP		iocp = (IOCP)mp->b_rptr;
 	conn_t		*connp;
+	boolean_t	gcgrp_xtraref = B_FALSE;
+	tsol_gcgrp_addr_t ga;
+	tsol_rtsecattr_t rtsecattr;
+	struct rtsa_s	*rtsap = NULL;
+	tsol_gcgrp_t	*gcgrp = NULL;
+	tsol_gc_t	*gc = NULL;
 
 	ip1dbg(("ip_rts_request: mp is %x\n", DB_TYPE(mp)));
 
@@ -347,7 +352,12 @@
 	}
 
 	found_addrs = rts_getaddrs(rtm, &dst_addr_v6, &gw_addr_v6, &net_mask_v6,
-	    &author_v6, &if_addr_v6, &src_addr_v6, &index, &src_index, &af);
+	    &author_v6, &if_addr_v6, &src_addr_v6, &index, &src_index, &af,
+	    &rtsecattr, &error);
+
+	if (error != 0)
+		goto done;
+
 	if ((found_addrs & RTA_DST) == 0) {
 		error = EINVAL;
 		goto done;
@@ -471,6 +481,16 @@
 	if ((found_addrs & RTA_NETMASK) != 0)
 		match_flags |= MATCH_IRE_MASK;
 
+	/*
+	 * We only process any passed-in route security attributes for
+	 * either RTM_ADD or RTM_CHANGE message; ignore otherwise.
+	 */
+	if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) {
+		ASSERT(rtsecattr.rtsa_cnt <= TSOL_RTSA_REQUEST_MAX);
+		if (rtsecattr.rtsa_cnt > 0)
+			rtsap = &rtsecattr.rtsa_attr[0];
+	}
+
 	switch (rtm->rtm_type) {
 	case RTM_ADD:
 		/* if we are adding a route, gateway is a must */
@@ -554,10 +574,10 @@
 				}
 			}
 
-			error = ip_rt_add(dst_addr, net_mask,
-			    gw_addr, src_addr,
+			error = ip_rt_add(dst_addr, net_mask, gw_addr, src_addr,
 			    rtm->rtm_flags, ipif, src_ipif, &ire, B_FALSE,
-			    CONNP_TO_WQ(connp), ioc_mp, ip_rts_request_retry);
+			    CONNP_TO_WQ(connp), ioc_mp, ip_rts_request_retry,
+			    rtsap);
 			if (ipif != NULL)
 				ASSERT(!MUTEX_HELD(&ipif->ipif_ill->ill_lock));
 			break;
@@ -605,7 +625,7 @@
 				error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6,
 				    &gw_addr_v6, &src_addr_v6, rtm->rtm_flags,
 				    ipif, &ire, CONNP_TO_WQ(connp), ioc_mp,
-				    ip_rts_request_retry);
+				    ip_rts_request_retry, rtsap);
 				break;
 			}
 			/*
@@ -619,7 +639,7 @@
 			error = ip_rt_add_v6(&dst_addr_v6, &net_mask_v6,
 			    &gw_addr_v6, NULL, rtm->rtm_flags,
 			    ipif, &ire, CONNP_TO_WQ(connp), ioc_mp,
-			    ip_rts_request_retry);
+			    ip_rts_request_retry, rtsap);
 			if (ipif != NULL)
 				ASSERT(!MUTEX_HELD(&ipif->ipif_ill->ill_lock));
 			break;
@@ -726,24 +746,25 @@
 			if (net_mask == IP_HOST_MASK) {
 				ire = ire_ctable_lookup(dst_addr, gw_addr,
 				    IRE_LOCAL | IRE_LOOPBACK, NULL, ALL_ZONES,
-				    MATCH_IRE_TYPE | MATCH_IRE_GW);
+				    NULL, MATCH_IRE_TYPE | MATCH_IRE_GW);
 			}
 			if (ire == NULL) {
 				ire = ire_ftable_lookup(dst_addr, net_mask,
 				    gw_addr, 0, ipif, &sire, ALL_ZONES, 0,
-				    match_flags);
+				    NULL, match_flags);
 			}
 			break;
 		case AF_INET6:
 			if (IN6_ARE_ADDR_EQUAL(&net_mask_v6, &ipv6_all_ones)) {
 				ire = ire_ctable_lookup_v6(&dst_addr_v6,
 				    &gw_addr_v6, IRE_LOCAL | IRE_LOOPBACK, NULL,
-				    ALL_ZONES, MATCH_IRE_TYPE | MATCH_IRE_GW);
+				    ALL_ZONES, NULL,
+				    MATCH_IRE_TYPE | MATCH_IRE_GW);
 			}
 			if (ire == NULL) {
 				ire = ire_ftable_lookup_v6(&dst_addr_v6,
 				    &net_mask_v6, &gw_addr_v6, 0, ipif, &sire,
-				    ALL_ZONES, 0, match_flags);
+				    ALL_ZONES, 0, NULL, match_flags);
 			}
 			break;
 		}
@@ -790,6 +811,19 @@
 				    (ire->ire_gateway_addr != gw_addr)) {
 					ire->ire_gateway_addr = gw_addr;
 				}
+
+				if (rtsap != NULL) {
+					ga.ga_af = AF_INET;
+					IN6_IPADDR_TO_V4MAPPED(
+					    ire->ire_gateway_addr, &ga.ga_addr);
+
+					gcgrp = gcgrp_lookup(&ga, B_TRUE);
+					if (gcgrp == NULL) {
+						error = ENOMEM;
+						goto done;
+					}
+				}
+
 				if ((found_addrs & RTA_SRC) != 0 &&
 				    (rtm->rtm_flags & RTF_SETSRC) != 0 &&
 				    (ire->ire_src_addr != src_addr)) {
@@ -849,6 +883,18 @@
 				    &ire->ire_gateway_addr_v6, &gw_addr_v6)) {
 					ire->ire_gateway_addr_v6 = gw_addr_v6;
 				}
+
+				if (rtsap != NULL) {
+					ga.ga_af = AF_INET6;
+					ga.ga_addr = ire->ire_gateway_addr_v6;
+
+					gcgrp = gcgrp_lookup(&ga, B_TRUE);
+					if (gcgrp == NULL) {
+						error = ENOMEM;
+						goto done;
+					}
+				}
+
 				if ((found_addrs & RTA_SRC) != 0 &&
 				    (rtm->rtm_flags & RTF_SETSRC) != 0 &&
 				    !IN6_ARE_ADDR_EQUAL(
@@ -910,6 +956,48 @@
 				mutex_exit(&ire->ire_lock);
 				break;
 			}
+
+			if (rtsap != NULL) {
+				in_addr_t ga_addr4;
+
+				ASSERT(gcgrp != NULL);
+
+				/*
+				 * Create and add the security attribute to
+				 * prefix IRE; it will add a reference to the
+				 * group upon allocating a new entry.  If it
+				 * finds an already-existing entry for the
+				 * security attribute, it simply returns it
+				 * and no new group reference is made.
+				 */
+				gc = gc_create(rtsap, gcgrp, &gcgrp_xtraref);
+				if (gc == NULL ||
+				    (error = tsol_ire_init_gwattr(ire,
+				    ire->ire_ipversion, gc, NULL)) != 0) {
+					if (gc != NULL) {
+						GC_REFRELE(gc);
+					} else {
+						/* gc_create failed */
+						error = ENOMEM;
+					}
+					goto done;
+				}
+
+				/*
+				 * Now delete any existing gateway IRE caches
+				 * as well as all caches using the gateway,
+				 * and allow them to be created on demand
+				 * through ip_newroute{_v6}.
+				 */
+				IN6_V4MAPPED_TO_IPADDR(&ga.ga_addr, ga_addr4);
+				if (af == AF_INET) {
+					ire_clookup_delete_cache_gw(
+					    ga_addr4, ALL_ZONES);
+				} else {
+					ire_clookup_delete_cache_gw_v6(
+					    &ga.ga_addr, ALL_ZONES);
+				}
+			}
 			rts_setmetrics(ire, rtm->rtm_inits, &rtm->rtm_rmx);
 			break;
 		}
@@ -930,6 +1018,9 @@
 	if (tmp_ipif != NULL)
 		ipif_refrele(tmp_ipif);
 
+	if (gcgrp_xtraref)
+		GCGRP_REFRELE(gcgrp);
+
 	if (error == EINPROGRESS)
 		return (error);
 	if (rtm != NULL) {
@@ -964,7 +1055,7 @@
  * Returns a pointer to a message block containing the reply if successful,
  * otherwise NULL is returned.
  */
-mblk_t *
+static mblk_t *
 rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af)
 {
 	rt_msghdr_t	*rtm;
@@ -973,10 +1064,49 @@
 	int		rtm_addrs;
 	int		rtm_flags;
 	in6_addr_t	gw_addr_v6;
+	tsol_ire_gw_secattr_t *attrp = NULL;
+	tsol_gc_t	*gc = NULL;
+	tsol_gcgrp_t	*gcgrp = NULL;
+	int		sacnt = 0;
 
 	ASSERT(ire->ire_ipif != NULL);
 	rtm = (rt_msghdr_t *)mp->b_rptr;
 
+	if (sire != NULL && sire->ire_gw_secattr != NULL)
+		attrp = sire->ire_gw_secattr;
+	else if (ire->ire_gw_secattr != NULL)
+		attrp = ire->ire_gw_secattr;
+
+	if (attrp != NULL) {
+		mutex_enter(&attrp->igsa_lock);
+		if ((gc = attrp->igsa_gc) != NULL) {
+			gcgrp = gc->gc_grp;
+			ASSERT(gcgrp != NULL);
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			sacnt = 1;
+		} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {
+			rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+			gc = gcgrp->gcgrp_head;
+			sacnt = gcgrp->gcgrp_count;
+		}
+		mutex_exit(&attrp->igsa_lock);
+
+		/* do nothing if there's no gc to report */
+		if (gc == NULL) {
+			ASSERT(sacnt == 0);
+			if (gcgrp != NULL) {
+				/* we might as well drop the lock now */
+				rw_exit(&gcgrp->gcgrp_rwlock);
+				gcgrp = NULL;
+			}
+			attrp = NULL;
+		}
+
+		ASSERT(gc == NULL || (gcgrp != NULL &&
+		    RW_LOCK_HELD(&gcgrp->gcgrp_rwlock)));
+	}
+	ASSERT(sacnt == 0 || gc != NULL);
+
 	/*
 	 * Always return RTA_DST, RTA_GATEWAY and RTA_NETMASK.
 	 *
@@ -992,9 +1122,12 @@
 			rtm_addrs |= RTA_BRD;
 	}
 
-	new_mp = rts_alloc_msg(RTM_GET, rtm_addrs, af);
-	if (new_mp == NULL)
+	new_mp = rts_alloc_msg(RTM_GET, rtm_addrs, af, sacnt);
+	if (new_mp == NULL) {
+		if (gcgrp != NULL)
+			rw_exit(&gcgrp->gcgrp_rwlock);
 		return (NULL);
+	}
 
 	/*
 	 * We set the destination address, gateway address,
@@ -1013,7 +1146,7 @@
 			rts_fill_msg(RTM_GET, rtm_addrs, ire->ire_addr,
 			    ire->ire_mask, ire->ire_src_addr, ire->ire_src_addr,
 			    ire->ire_ipif->ipif_pp_dst_addr, 0, ire->ire_ipif,
-			    new_mp);
+			    new_mp, sacnt, gc);
 		} else {
 			if (sire->ire_flags & RTF_SETSRC)
 				rtm_addrs |= RTA_SRC;
@@ -1024,7 +1157,7 @@
 			    (sire->ire_flags & RTF_SETSRC) ?
 				sire->ire_src_addr : ire->ire_src_addr,
 			    ire->ire_ipif->ipif_pp_dst_addr,
-			    0, ire->ire_ipif, new_mp);
+			    0, ire->ire_ipif, new_mp, sacnt, gc);
 		}
 		break;
 	case AF_INET6:
@@ -1034,7 +1167,8 @@
 			    &ire->ire_mask_v6, &ire->ire_src_addr_v6,
 			    &ire->ire_src_addr_v6,
 			    &ire->ire_ipif->ipif_v6pp_dst_addr,
-			    &ipv6_all_zeros, ire->ire_ipif, new_mp);
+			    &ipv6_all_zeros, ire->ire_ipif, new_mp,
+			    sacnt, gc);
 		} else {
 			if (sire->ire_flags & RTF_SETSRC)
 				rtm_addrs |= RTA_SRC;
@@ -1048,10 +1182,14 @@
 			    (sire->ire_flags & RTF_SETSRC) ?
 				&sire->ire_src_addr_v6 : &ire->ire_src_addr_v6,
 			    &ire->ire_ipif->ipif_v6pp_dst_addr, &ipv6_all_zeros,
-			    ire->ire_ipif, new_mp);
+			    ire->ire_ipif, new_mp, sacnt, gc);
 		}
 		break;
 	}
+
+	if (gcgrp != NULL)
+		rw_exit(&gcgrp->gcgrp_rwlock);
+
 	new_rtm = (rt_msghdr_t *)new_mp->b_rptr;
 
 	/*
@@ -1079,6 +1217,7 @@
 		new_rtm->rtm_inits = rts_getmetrics(ire, &new_rtm->rtm_rmx);
 	else
 		new_rtm->rtm_inits = rts_getmetrics(sire, &new_rtm->rtm_rmx);
+
 	return (new_mp);
 }
 
@@ -1086,7 +1225,7 @@
  * Fill the given if_data_t with interface statistics.
  */
 static void
-rts_getifdata(if_data_t *if_data, ipif_t *ipif)
+rts_getifdata(if_data_t *if_data, const ipif_t *ipif)
 {
 	if_data->ifi_type = ipif->ipif_type;	/* ethernet, tokenring, etc */
 	if_data->ifi_addrlen = 0;		/* media address length */
@@ -1254,7 +1393,7 @@
 rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_addrp,
     in6_addr_t *net_maskp, in6_addr_t *authorp, in6_addr_t *if_addrp,
     in6_addr_t *in_src_addrp, ushort_t *indexp, ushort_t *src_indexp,
-    sa_family_t *afp)
+    sa_family_t *afp, tsol_rtsecattr_t *rtsecattr, int *error)
 {
 	struct sockaddr *sa;
 	int	i;
@@ -1274,6 +1413,8 @@
 	*indexp = 0;
 	*src_indexp = 0;
 	*afp = AF_UNSPEC;
+	rtsecattr->rtsa_cnt = 0;
+	*error = 0;
 
 	/*
 	 * At present we handle only RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_IFP,
@@ -1354,6 +1495,16 @@
 		cp += size;
 		found_addrs |= addr_bits;
 	}
+
+	/*
+	 * Parse the routing message and look for any security-
+	 * related attributes for the route.  For each valid
+	 * attribute, allocate/obtain the corresponding kernel
+	 * route security attributes.
+	 */
+	*error = tsol_rtsa_init(rtm, rtsecattr, cp);
+	ASSERT(rtsecattr->rtsa_cnt <= TSOL_RTSA_REQUEST_MAX);
+
 	return (found_addrs);
 }
 
@@ -1363,7 +1514,7 @@
 static void
 rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask,
     ipaddr_t gateway, ipaddr_t src_addr, ipaddr_t brd_addr, ipaddr_t author,
-    ipif_t *ipif, mblk_t *mp)
+    const ipif_t *ipif, mblk_t *mp, uint_t sacnt, const tsol_gc_t *gc)
 {
 	rt_msghdr_t	*rtm;
 	sin_t		*sin;
@@ -1372,6 +1523,7 @@
 	int		i;
 
 	ASSERT(mp != NULL);
+	ASSERT(sacnt == 0 || gc != NULL);
 	/*
 	 * First find the type of the message
 	 * and its length.
@@ -1381,7 +1533,7 @@
 	 * Now find the size of the data
 	 * that follows the message header.
 	 */
-	data_size = rts_data_msg_size(rtm_addrs, AF_INET);
+	data_size = rts_data_msg_size(rtm_addrs, AF_INET, sacnt);
 
 	rtm = (rt_msghdr_t *)mp->b_rptr;
 	mp->b_wptr = &mp->b_rptr[header_size];
@@ -1436,6 +1588,32 @@
 			break;
 		}
 	}
+
+	if (gc != NULL) {
+		rtm_ext_t *rtm_ext;
+		struct rtsa_s *rp_dst;
+		tsol_rtsecattr_t *rsap;
+		int i;
+
+		ASSERT(gc->gc_grp != NULL);
+		ASSERT(RW_LOCK_HELD(&gc->gc_grp->gcgrp_rwlock));
+		ASSERT(sacnt > 0);
+
+		rtm_ext = (rtm_ext_t *)cp;
+		rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR;
+		rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(sacnt);
+
+		rsap = (tsol_rtsecattr_t *)(rtm_ext + 1);
+		rsap->rtsa_cnt = sacnt;
+		rp_dst = rsap->rtsa_attr;
+
+		for (i = 0; i < sacnt; i++, gc = gc->gc_next, rp_dst++) {
+			ASSERT(gc->gc_db != NULL);
+			bcopy(&gc->gc_db->gcdb_attr, rp_dst, sizeof (*rp_dst));
+		}
+		cp = (uchar_t *)rp_dst;
+	}
+
 	mp->b_wptr = cp;
 	mp->b_cont = NULL;
 	/*
@@ -1451,12 +1629,12 @@
  * Allocates and initializes a routing socket message.
  */
 mblk_t *
-rts_alloc_msg(int type, int rtm_addrs, sa_family_t af)
+rts_alloc_msg(int type, int rtm_addrs, sa_family_t af, uint_t sacnt)
 {
 	size_t	length;
 	mblk_t	*mp;
 
-	length = RTS_MSG_SIZE(type, rtm_addrs, af);
+	length = RTS_MSG_SIZE(type, rtm_addrs, af, sacnt);
 	mp = allocb(length, BPRI_MED);
 	if (mp == NULL)
 		return (mp);
@@ -1489,7 +1667,7 @@
  * of the same family (currently either AF_INET or AF_INET6).
  */
 size_t
-rts_data_msg_size(int rtm_addrs, sa_family_t af)
+rts_data_msg_size(int rtm_addrs, sa_family_t af, uint_t sacnt)
 {
 	int	i;
 	size_t	length = 0;
@@ -1519,6 +1697,9 @@
 			break;
 		}
 	}
+	if (sacnt > 0)
+		length += sizeof (rtm_ext_t) + TSOL_RTSECATTR_SIZE(sacnt);
+
 	return (length);
 }
 
@@ -1538,11 +1719,11 @@
 
 	if (rtm_addrs == 0)
 		return;
-	mp = rts_alloc_msg(type, rtm_addrs, AF_INET);
+	mp = rts_alloc_msg(type, rtm_addrs, AF_INET, 0);
 	if (mp == NULL)
 		return;
 	rts_fill_msg(type, rtm_addrs, dst_addr, net_mask, gw_addr, source, 0,
-	    author, NULL, mp);
+	    author, NULL, mp, 0, NULL);
 	rtm = (rt_msghdr_t *)mp->b_rptr;
 	rtm->rtm_flags = flags;
 	rtm->rtm_errno = error;
@@ -1557,7 +1738,7 @@
  * Message type generated RTM_IFINFO.
  */
 void
-ip_rts_ifmsg(ipif_t *ipif)
+ip_rts_ifmsg(const ipif_t *ipif)
 {
 	if_msghdr_t	*ifm;
 	mblk_t		*mp;
@@ -1572,18 +1753,19 @@
 		return;
 	if (ipif->ipif_isv6) {
 		af = AF_INET6;
-		mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af);
+		mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0);
 		if (mp == NULL)
 			return;
 		rts_fill_msg_v6(RTM_IFINFO, RTA_IFP, &ipv6_all_zeros,
 		    &ipv6_all_zeros, &ipv6_all_zeros, &ipv6_all_zeros,
-		    &ipv6_all_zeros, &ipv6_all_zeros, ipif, mp);
+		    &ipv6_all_zeros, &ipv6_all_zeros, ipif, mp, 0, NULL);
 	} else {
 		af = AF_INET;
-		mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af);
+		mp = rts_alloc_msg(RTM_IFINFO, RTA_IFP, af, 0);
 		if (mp == NULL)
 			return;
-		rts_fill_msg(RTM_IFINFO, RTA_IFP, 0, 0, 0, 0, 0, 0, ipif, mp);
+		rts_fill_msg(RTM_IFINFO, RTA_IFP, 0, 0, 0, 0, 0, 0, ipif, mp,
+		    0, NULL);
 	}
 	ifm = (if_msghdr_t *)mp->b_rptr;
 	ifm->ifm_index = ipif->ipif_ill->ill_phyint->phyint_ifindex;
@@ -1600,7 +1782,7 @@
  * The structure of the code is based on the 4.4BSD-Lite2 <net/rtsock.c>.
  */
 void
-ip_rts_newaddrmsg(int cmd, int error, ipif_t *ipif)
+ip_rts_newaddrmsg(int cmd, int error, const ipif_t *ipif)
 {
 	int		pass;
 	int		ncmd;
@@ -1624,21 +1806,22 @@
 			ncmd = ((cmd == RTM_ADD) ? RTM_NEWADDR : RTM_DELADDR);
 
 			rtm_addrs = (RTA_IFA | RTA_NETMASK | RTA_BRD);
-			mp = rts_alloc_msg(ncmd, rtm_addrs, af);
+			mp = rts_alloc_msg(ncmd, rtm_addrs, af, 0);
 			if (mp == NULL)
 				continue;
 			switch (af) {
 			case AF_INET:
 				rts_fill_msg(ncmd, rtm_addrs, 0,
 				    ipif->ipif_net_mask, 0, ipif->ipif_lcl_addr,
-				    ipif->ipif_pp_dst_addr, 0, NULL, mp);
+				    ipif->ipif_pp_dst_addr, 0, NULL, mp,
+				    0, NULL);
 				break;
 			case AF_INET6:
 				rts_fill_msg_v6(ncmd, rtm_addrs,
 				    &ipv6_all_zeros, &ipif->ipif_v6net_mask,
 				    &ipv6_all_zeros, &ipif->ipif_v6lcl_addr,
 				    &ipif->ipif_v6pp_dst_addr, &ipv6_all_zeros,
-				    NULL, mp);
+				    NULL, mp, 0, NULL);
 				break;
 			}
 			ifam = (ifa_msghdr_t *)mp->b_rptr;
@@ -1652,21 +1835,21 @@
 		if ((cmd == RTM_ADD && pass == 2) ||
 		    (cmd == RTM_DELETE && pass == 1)) {
 			rtm_addrs = (RTA_DST | RTA_NETMASK);
-			mp = rts_alloc_msg(cmd, rtm_addrs, af);
+			mp = rts_alloc_msg(cmd, rtm_addrs, af, 0);
 			if (mp == NULL)
 				continue;
 			switch (af) {
 			case AF_INET:
 				rts_fill_msg(cmd, rtm_addrs,
 				    ipif->ipif_lcl_addr, ipif->ipif_net_mask, 0,
-				    0, 0, 0, NULL, mp);
+				    0, 0, 0, NULL, mp, 0, NULL);
 				break;
 			case AF_INET6:
 				rts_fill_msg_v6(cmd, rtm_addrs,
 				    &ipif->ipif_v6lcl_addr,
 				    &ipif->ipif_v6net_mask, &ipv6_all_zeros,
 				    &ipv6_all_zeros, &ipv6_all_zeros,
-				    &ipv6_all_zeros, NULL, mp);
+				    &ipv6_all_zeros, NULL, mp, 0, NULL);
 				break;
 			}
 			rtm = (rt_msghdr_t *)mp->b_rptr;
--- a/usr/src/uts/common/inet/ip/ipclassifier.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ipclassifier.c	Fri Mar 24 12:29:20 2006 -0800
@@ -25,7 +25,7 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-const char ipclassifier_version[] = "@(#)ipclassifier.c	1.6	04/03/31 SMI";
+const char ipclassifier_version[] = "@(#)ipclassifier.c	%I%	%E% SMI";
 
 /*
  * IP PACKET CLASSIFIER
@@ -110,7 +110,9 @@
  *	hdr_len: The size of IP header. It is used to find TCP or UDP header in
  *		 the packet.
  *
- * 	zoneid: The zone in which the returned connection must be.
+ * 	zoneid: The zone in which the returned connection must be; the zoneid
+ *		corresponding to the ire_zoneid on the IRE located for the
+ *		packet's destination address.
  *
  *	For TCP connections, the lookup order is as follows:
  *		5-tuple {src, dst, protocol, local port, remote port}
@@ -123,6 +125,40 @@
  *	these interfaces do not handle cases where a packets belongs
  *	to multiple UDP clients, which is handled in IP itself.
  *
+ * If the destination IRE is ALL_ZONES (indicated by zoneid), then we must
+ * determine which actual zone gets the segment.  This is used only in a
+ * labeled environment.  The matching rules are:
+ *
+ *	- If it's not a multilevel port, then the label on the packet selects
+ *	  the zone.  Unlabeled packets are delivered to the global zone.
+ *
+ *	- If it's a multilevel port, then only the zone registered to receive
+ *	  packets on that port matches.
+ *
+ * Also, in a labeled environment, packet labels need to be checked.  For fully
+ * bound TCP connections, we can assume that the packet label was checked
+ * during connection establishment, and doesn't need to be checked on each
+ * packet.  For others, though, we need to check for strict equality or, for
+ * multilevel ports, membership in the range or set.  This part currently does
+ * a tnrh lookup on each packet, but could be optimized to use cached results
+ * if that were necessary.  (SCTP doesn't come through here, but if it did,
+ * we would apply the same rules as TCP.)
+ *
+ * An implication of the above is that fully-bound TCP sockets must always use
+ * distinct 4-tuples; they can't be discriminated by label alone.
+ *
+ * Note that we cannot trust labels on packets sent to fully-bound UDP sockets,
+ * as there's no connection set-up handshake and no shared state.
+ *
+ * Labels on looped-back packets within a single zone do not need to be
+ * checked, as all processes in the same zone have the same label.
+ *
+ * Finally, for unlabeled packets received by a labeled system, special rules
+ * apply.  We consider only the MLP if there is one.  Otherwise, we prefer a
+ * socket in the zone whose label matches the default label of the sender, if
+ * any.  In any event, the receiving socket must have SO_MAC_EXEMPT set and the
+ * receiver's label must dominate the sender's default label.
+ *
  * conn_t	*ipcl_tcp_lookup_reversed_ipv4(ipha_t *, tcph_t *, int);
  * conn_t	*ipcl_tcp_lookup_reversed_ipv6(ip6_t *, tcpha_t *, int, uint_t);
  *
@@ -203,11 +239,9 @@
 
 #include <sys/types.h>
 #include <sys/stream.h>
-#include <sys/dlpi.h>
 #include <sys/stropts.h>
 #include <sys/sysmacros.h>
 #include <sys/strsubr.h>
-#include <sys/strlog.h>
 #include <sys/strsun.h>
 #define	_SUN_TPI_VERSION 2
 #include <sys/ddi.h>
@@ -225,24 +259,17 @@
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/tcp.h>
-#include <inet/tcp_trace.h>
-#include <inet/ip_multi.h>
-#include <inet/ip_if.h>
-#include <inet/ip_ire.h>
-#include <inet/ip_rts.h>
-#include <inet/optcom.h>
 #include <inet/ip_ndp.h>
 #include <inet/udp_impl.h>
 #include <inet/sctp_ip.h>
 
-#include <sys/ethernet.h>
-#include <net/if_types.h>
 #include <sys/cpuvar.h>
 
-#include <inet/mi.h>
 #include <inet/ipclassifier.h>
 #include <inet/ipsec_impl.h>
 
+#include <sys/tsol/tnet.h>
+
 #ifdef DEBUG
 #define	IPCL_DEBUG
 #else
@@ -527,6 +554,16 @@
 	ASSERT(connp->conn_ref == 0);
 	ASSERT(connp->conn_ire_cache == NULL);
 
+	if (connp->conn_peercred != NULL &&
+	    connp->conn_peercred != connp->conn_cred)
+		crfree(connp->conn_peercred);
+	connp->conn_peercred = NULL;
+
+	if (connp->conn_cred != NULL) {
+		crfree(connp->conn_cred);
+		connp->conn_cred = NULL;
+	}
+
 	ipcl_globalhash_remove(connp);
 
 	cv_destroy(&connp->conn_cv);
@@ -537,6 +574,7 @@
 		ASSERT(connp->conn_tcp != NULL);
 		tcp_free(tcp);
 		mp = tcp->tcp_timercache;
+		tcp->tcp_cred = NULL;
 
 		if (tcp->tcp_sack_info != NULL) {
 			bzero(tcp->tcp_sack_info, sizeof (tcp_sack_info_t));
@@ -763,6 +801,7 @@
 void
 ipcl_hash_insert_wildcard(connf_t *connfp, conn_t *connp)
 {
+	ASSERT(!connp->conn_mac_exempt);
 	IPCL_HASH_INSERT_WILDCARD(connfp, connp);
 }
 
@@ -772,6 +811,8 @@
 	connf_t	*connfp;
 
 	ASSERT(connp != NULL);
+	ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
+	    protocol == IPPROTO_ESP);
 
 	connp->conn_ulp = protocol;
 
@@ -786,6 +827,8 @@
 	connf_t	*connfp;
 
 	ASSERT(connp != NULL);
+	ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
+	    protocol == IPPROTO_ESP);
 
 	connp->conn_ulp = protocol;
 
@@ -844,6 +887,69 @@
 }
 
 /*
+ * Check for a MAC exemption conflict on a labeled system.  Note that for
+ * protocols that use port numbers (UDP, TCP, SCTP), we do this check up in the
+ * transport layer.  This check is for binding all other protocols.
+ *
+ * Returns true if there's a conflict.
+ */
+static boolean_t
+check_exempt_conflict_v4(conn_t *connp)
+{
+	connf_t	*connfp;
+	conn_t *tconn;
+
+	connfp = &ipcl_proto_fanout[connp->conn_ulp];
+	mutex_enter(&connfp->connf_lock);
+	for (tconn = connfp->connf_head; tconn != NULL;
+	    tconn = tconn->conn_next) {
+		/* We don't allow v4 fallback for v6 raw socket */
+		if (connp->conn_af_isv6 != tconn->conn_af_isv6)
+			continue;
+		/* If neither is exempt, then there's no conflict */
+		if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+			continue;
+		/* If both are bound to different specific addrs, ok */
+		if (connp->conn_src != INADDR_ANY &&
+		    tconn->conn_src != INADDR_ANY &&
+		    connp->conn_src != tconn->conn_src)
+			continue;
+		/* These two conflict; fail */
+		break;
+	}
+	mutex_exit(&connfp->connf_lock);
+	return (tconn != NULL);
+}
+
+static boolean_t
+check_exempt_conflict_v6(conn_t *connp)
+{
+	connf_t	*connfp;
+	conn_t *tconn;
+
+	connfp = &ipcl_proto_fanout[connp->conn_ulp];
+	mutex_enter(&connfp->connf_lock);
+	for (tconn = connfp->connf_head; tconn != NULL;
+	    tconn = tconn->conn_next) {
+		/* We don't allow v4 fallback for v6 raw socket */
+		if (connp->conn_af_isv6 != tconn->conn_af_isv6)
+			continue;
+		/* If neither is exempt, then there's no conflict */
+		if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+			continue;
+		/* If both are bound to different addrs, ok */
+		if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_srcv6) &&
+		    !IN6_IS_ADDR_UNSPECIFIED(&tconn->conn_srcv6) &&
+		    !IN6_ARE_ADDR_EQUAL(&connp->conn_srcv6, &tconn->conn_srcv6))
+			continue;
+		/* These two conflict; fail */
+		break;
+	}
+	mutex_exit(&connfp->connf_lock);
+	return (tconn != NULL);
+}
+
+/*
  * (v4, v6) bind hash insertion routines
  */
 int
@@ -865,8 +971,11 @@
 	connp->conn_lport = lport;
 
 	switch (protocol) {
+	default:
+		if (is_system_labeled() && check_exempt_conflict_v4(connp))
+			return (EADDRINUSE);
+		/* FALLTHROUGH */
 	case IPPROTO_UDP:
-	default:
 		if (protocol == IPPROTO_UDP) {
 			IPCL_DEBUG_LVL(64,
 			    ("ipcl_bind_insert: connp %p - udp\n",
@@ -891,6 +1000,7 @@
 	case IPPROTO_TCP:
 
 		/* Insert it in the Bind Hash */
+		ASSERT(connp->conn_zoneid != ALL_ZONES);
 		connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 		if (connp->conn_src != INADDR_ANY) {
 			IPCL_HASH_INSERT_BOUND(connfp, connp);
@@ -927,8 +1037,11 @@
 	connp->conn_lport = lport;
 
 	switch (protocol) {
+	default:
+		if (is_system_labeled() && check_exempt_conflict_v6(connp))
+			return (EADDRINUSE);
+		/* FALLTHROUGH */
 	case IPPROTO_UDP:
-	default:
 		if (protocol == IPPROTO_UDP) {
 			IPCL_DEBUG_LVL(128,
 			    ("ipcl_bind_insert_v6: connp %p - udp\n",
@@ -954,6 +1067,7 @@
 		/* XXX - Need a separate table for IN6_IS_ADDR_UNSPECIFIED? */
 
 		/* Insert it in the Bind Hash */
+		ASSERT(connp->conn_zoneid != ALL_ZONES);
 		connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 		if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_srcv6)) {
 			IPCL_HASH_INSERT_BOUND(connfp, connp);
@@ -1055,8 +1169,18 @@
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
 
+	default:
+		/*
+		 * Check for conflicts among MAC exempt bindings.  For
+		 * transports with port numbers, this is done by the upper
+		 * level per-transport binding logic.  For all others, it's
+		 * done here.
+		 */
+		if (is_system_labeled() && check_exempt_conflict_v4(connp))
+			return (EADDRINUSE);
+		/* FALLTHROUGH */
+
 	case IPPROTO_UDP:
-	default:
 		up = (uint16_t *)&ports;
 		IPCL_CONN_INIT(connp, protocol, src, rem, ports);
 		if (protocol == IPPROTO_UDP) {
@@ -1128,8 +1252,11 @@
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
 
+	default:
+		if (is_system_labeled() && check_exempt_conflict_v6(connp))
+			return (EADDRINUSE);
+		/* FALLTHROUGH */
 	case IPPROTO_UDP:
-	default:
 		up = (uint16_t *)&ports;
 		IPCL_CONN_INIT_V6(connp, protocol, *src, *rem, ports);
 		if (protocol == IPPROTO_UDP) {
@@ -1155,6 +1282,11 @@
  * v4 packet classifying function. looks up the fanout table to
  * find the conn, the packet belongs to. returns the conn with
  * the reference held, null otherwise.
+ *
+ * If zoneid is ALL_ZONES, then the search rules described in the "Connection
+ * Lookup" comment block are applied.  Labels are also checked as described
+ * above.  If the packet is from the inside (looped back), and is from the same
+ * zone, then label checks are omitted.
  */
 conn_t *
 ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid)
@@ -1166,6 +1298,8 @@
 	uint32_t ports;
 	conn_t	*connp;
 	uint16_t  *up;
+	boolean_t shared_addr;
+	boolean_t unlabeled;
 
 	ipha = (ipha_t *)mp->b_rptr;
 	up = (uint16_t *)((uchar_t *)ipha + hdr_len + TCP_PORTS_OFFSET);
@@ -1184,6 +1318,13 @@
 		}
 
 		if (connp != NULL) {
+			/*
+			 * We have a fully-bound TCP connection.
+			 *
+			 * For labeled systems, there's no need to check the
+			 * label here.  It's known to be good as we checked
+			 * before allowing the connection to become bound.
+			 */
 			CONN_INC_REF(connp);
 			mutex_exit(&connfp->connf_lock);
 			return (connp);
@@ -1192,18 +1333,60 @@
 		mutex_exit(&connfp->connf_lock);
 
 		lport = up[1];
+		unlabeled = B_FALSE;
+		/* Cred cannot be null on IPv4 */
+		if (is_system_labeled())
+			unlabeled = (crgetlabel(DB_CRED(mp))->tsl_flags &
+			    TSLF_UNLABELED) != 0;
+		shared_addr = (zoneid == ALL_ZONES);
+		if (shared_addr) {
+			zoneid = tsol_mlp_findzone(protocol, lport);
+			/*
+			 * If no shared MLP is found, tsol_mlp_findzone returns
+			 * ALL_ZONES.  In that case, we assume it's SLP, and
+			 * search for the zone based on the packet label.
+			 *
+			 * If there is such a zone, we prefer to find a
+			 * connection in it.  Otherwise, we look for a
+			 * MAC-exempt connection in any zone whose label
+			 * dominates the default label on the packet.
+			 */
+			if (zoneid == ALL_ZONES)
+				zoneid = tsol_packet_to_zoneid(mp);
+			else
+				unlabeled = B_FALSE;
+		}
+
 		bind_connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 		mutex_enter(&bind_connfp->connf_lock);
 		for (connp = bind_connfp->connf_head; connp != NULL;
 		    connp = connp->conn_next) {
-			if (IPCL_BIND_MATCH(connp, protocol,
-			    ipha->ipha_dst, lport) &&
-			    connp->conn_zoneid == zoneid)
+			if (IPCL_BIND_MATCH(connp, protocol, ipha->ipha_dst,
+			    lport) &&
+			    (connp->conn_zoneid == zoneid ||
+			    (unlabeled && connp->conn_mac_exempt)))
 				break;
 		}
 
+		/*
+		 * If the matching connection is SLP on a private address, then
+		 * the label on the packet must match the local zone's label.
+		 * Otherwise, it must be in the label range defined by tnrh.
+		 * This is ensured by tsol_receive_label.
+		 */
+		if (connp != NULL && is_system_labeled() &&
+		    !tsol_receive_local(mp, &ipha->ipha_dst, IPV4_VERSION,
+		    shared_addr, connp)) {
+				DTRACE_PROBE3(
+				    tx__ip__log__info__classify__tcp,
+				    char *,
+				    "connp(1) could not receive mp(2)",
+				    conn_t *, connp, mblk_t *, mp);
+			connp = NULL;
+		}
+
 		if (connp != NULL) {
-			/* Have a listner at least */
+			/* Have a listener at least */
 			CONN_INC_REF(connp);
 			mutex_exit(&bind_connfp->connf_lock);
 			return (connp);
@@ -1218,6 +1401,29 @@
 
 	case IPPROTO_UDP:
 		lport = up[1];
+		unlabeled = B_FALSE;
+		/* Cred cannot be null on IPv4 */
+		if (is_system_labeled())
+			unlabeled = (crgetlabel(DB_CRED(mp))->tsl_flags &
+			    TSLF_UNLABELED) != 0;
+		shared_addr = (zoneid == ALL_ZONES);
+		if (shared_addr) {
+			zoneid = tsol_mlp_findzone(protocol, lport);
+			/*
+			 * If no shared MLP is found, tsol_mlp_findzone returns
+			 * ALL_ZONES.  In that case, we assume it's SLP, and
+			 * search for the zone based on the packet label.
+			 *
+			 * If there is such a zone, we prefer to find a
+			 * connection in it.  Otherwise, we look for a
+			 * MAC-exempt connection in any zone whose label
+			 * dominates the default label on the packet.
+			 */
+			if (zoneid == ALL_ZONES)
+				zoneid = tsol_packet_to_zoneid(mp);
+			else
+				unlabeled = B_FALSE;
+		}
 		fport = up[0];
 		IPCL_DEBUG_LVL(512, ("ipcl_udp_classify %x %x", lport, fport));
 		connfp = &ipcl_udp_fanout[IPCL_UDP_HASH(lport)];
@@ -1226,10 +1432,20 @@
 		    connp = connp->conn_next) {
 			if (IPCL_UDP_MATCH(connp, lport, ipha->ipha_dst,
 			    fport, ipha->ipha_src) &&
-			    connp->conn_zoneid == zoneid)
+			    (connp->conn_zoneid == zoneid ||
+			    (unlabeled && connp->conn_mac_exempt)))
 				break;
 		}
 
+		if (connp != NULL && is_system_labeled() &&
+		    !tsol_receive_local(mp, &ipha->ipha_dst, IPV4_VERSION,
+		    shared_addr, connp)) {
+			DTRACE_PROBE3(tx__ip__log__info__classify__udp,
+			    char *, "connp(1) could not receive mp(2)",
+			    conn_t *, connp, mblk_t *, mp);
+			connp = NULL;
+		}
+
 		if (connp != NULL) {
 			CONN_INC_REF(connp);
 			mutex_exit(&connfp->connf_lock);
@@ -1260,7 +1476,8 @@
 	uint32_t	ports;
 	conn_t		*connp;
 	uint16_t	*up;
-
+	boolean_t	shared_addr;
+	boolean_t	unlabeled;
 
 	ip6h = (ip6_t *)mp->b_rptr;
 
@@ -1281,6 +1498,13 @@
 		}
 
 		if (connp != NULL) {
+			/*
+			 * We have a fully-bound TCP connection.
+			 *
+			 * For labeled systems, there's no need to check the
+			 * label here.  It's known to be good as we checked
+			 * before allowing the connection to become bound.
+			 */
 			CONN_INC_REF(connp);
 			mutex_exit(&connfp->connf_lock);
 			return (connp);
@@ -1289,16 +1513,53 @@
 		mutex_exit(&connfp->connf_lock);
 
 		lport = up[1];
+		unlabeled = B_FALSE;
+		/* Cred can be null on IPv6 */
+		if (is_system_labeled()) {
+			cred_t *cr = DB_CRED(mp);
+
+			unlabeled = (cr != NULL &&
+			    crgetlabel(cr)->tsl_flags & TSLF_UNLABELED) != 0;
+		}
+		shared_addr = (zoneid == ALL_ZONES);
+		if (shared_addr) {
+			zoneid = tsol_mlp_findzone(protocol, lport);
+			/*
+			 * If no shared MLP is found, tsol_mlp_findzone returns
+			 * ALL_ZONES.  In that case, we assume it's SLP, and
+			 * search for the zone based on the packet label.
+			 *
+			 * If there is such a zone, we prefer to find a
+			 * connection in it.  Otherwise, we look for a
+			 * MAC-exempt connection in any zone whose label
+			 * dominates the default label on the packet.
+			 */
+			if (zoneid == ALL_ZONES)
+				zoneid = tsol_packet_to_zoneid(mp);
+			else
+				unlabeled = B_FALSE;
+		}
+
 		bind_connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 		mutex_enter(&bind_connfp->connf_lock);
 		for (connp = bind_connfp->connf_head; connp != NULL;
 		    connp = connp->conn_next) {
 			if (IPCL_BIND_MATCH_V6(connp, protocol,
 			    ip6h->ip6_dst, lport) &&
-			    connp->conn_zoneid == zoneid)
+			    (connp->conn_zoneid == zoneid ||
+			    (unlabeled && connp->conn_mac_exempt)))
 				break;
 		}
 
+		if (connp != NULL && is_system_labeled() &&
+		    !tsol_receive_local(mp, &ip6h->ip6_dst, IPV6_VERSION,
+		    shared_addr, connp)) {
+			DTRACE_PROBE3(tx__ip__log__info__classify__tcp6,
+			    char *, "connp(1) could not receive mp(2)",
+			    conn_t *, connp, mblk_t *, mp);
+			connp = NULL;
+		}
+
 		if (connp != NULL) {
 			/* Have a listner at least */
 			CONN_INC_REF(connp);
@@ -1320,6 +1581,33 @@
 	case IPPROTO_UDP:
 		up = (uint16_t *)&mp->b_rptr[hdr_len];
 		lport = up[1];
+		unlabeled = B_FALSE;
+		/* Cred can be null on IPv6 */
+		if (is_system_labeled()) {
+			cred_t *cr = DB_CRED(mp);
+
+			unlabeled = (cr != NULL &&
+			    crgetlabel(cr)->tsl_flags & TSLF_UNLABELED) != 0;
+		}
+		shared_addr = (zoneid == ALL_ZONES);
+		if (shared_addr) {
+			zoneid = tsol_mlp_findzone(protocol, lport);
+			/*
+			 * If no shared MLP is found, tsol_mlp_findzone returns
+			 * ALL_ZONES.  In that case, we assume it's SLP, and
+			 * search for the zone based on the packet label.
+			 *
+			 * If there is such a zone, we prefer to find a
+			 * connection in it.  Otherwise, we look for a
+			 * MAC-exempt connection in any zone whose label
+			 * dominates the default label on the packet.
+			 */
+			if (zoneid == ALL_ZONES)
+				zoneid = tsol_packet_to_zoneid(mp);
+			else
+				unlabeled = B_FALSE;
+		}
+
 		fport = up[0];
 		IPCL_DEBUG_LVL(512, ("ipcl_udp_classify_v6 %x %x", lport,
 		    fport));
@@ -1329,10 +1617,20 @@
 		    connp = connp->conn_next) {
 			if (IPCL_UDP_MATCH_V6(connp, lport, ip6h->ip6_dst,
 			    fport, ip6h->ip6_src) &&
-			    connp->conn_zoneid == zoneid)
+			    (connp->conn_zoneid == zoneid ||
+			    (unlabeled && connp->conn_mac_exempt)))
 				break;
 		}
 
+		if (connp != NULL && is_system_labeled() &&
+		    !tsol_receive_local(mp, &ip6h->ip6_dst, IPV6_VERSION,
+		    shared_addr, connp)) {
+			DTRACE_PROBE3(tx__ip__log__info__classify__udp6,
+			    char *, "connp(1) could not receive mp(2)",
+			    conn_t *, connp, mblk_t *, mp);
+			connp = NULL;
+		}
+
 		if (connp != NULL) {
 			CONN_INC_REF(connp);
 			mutex_exit(&connfp->connf_lock);
@@ -1349,7 +1647,6 @@
 		break;
 	}
 
-
 	return (NULL);
 }
 
@@ -1384,52 +1681,96 @@
 }
 
 conn_t *
-ipcl_classify_raw(uint8_t protocol, zoneid_t zoneid, uint32_t ports,
-    ipha_t *hdr)
+ipcl_classify_raw(mblk_t *mp, uint8_t protocol, zoneid_t zoneid,
+    uint32_t ports, ipha_t *hdr)
 {
-	struct connf_s	*connfp;
+	connf_t		*connfp;
 	conn_t		*connp;
 	in_port_t	lport;
 	int		af;
+	boolean_t	shared_addr;
+	boolean_t	unlabeled;
+	const void	*dst;
 
 	lport = ((uint16_t *)&ports)[1];
+
+	unlabeled = B_FALSE;
+	/* Cred can be null on IPv6 */
+	if (is_system_labeled()) {
+		cred_t *cr = DB_CRED(mp);
+
+		unlabeled = (cr != NULL &&
+		    crgetlabel(cr)->tsl_flags & TSLF_UNLABELED) != 0;
+	}
+	shared_addr = (zoneid == ALL_ZONES);
+	if (shared_addr) {
+		zoneid = tsol_mlp_findzone(protocol, lport);
+		/*
+		 * If no shared MLP is found, tsol_mlp_findzone returns
+		 * ALL_ZONES.  In that case, we assume it's SLP, and search for
+		 * the zone based on the packet label.
+		 *
+		 * If there is such a zone, we prefer to find a connection in
+		 * it.  Otherwise, we look for a MAC-exempt connection in any
+		 * zone whose label dominates the default label on the packet.
+		 */
+		if (zoneid == ALL_ZONES)
+			zoneid = tsol_packet_to_zoneid(mp);
+		else
+			unlabeled = B_FALSE;
+	}
+
 	af = IPH_HDR_VERSION(hdr);
+	dst = af == IPV4_VERSION ? (const void *)&hdr->ipha_dst :
+	    (const void *)&((ip6_t *)hdr)->ip6_dst;
 	connfp = &ipcl_raw_fanout[IPCL_RAW_HASH(ntohs(lport))];
 
 	mutex_enter(&connfp->connf_lock);
 	for (connp = connfp->connf_head; connp != NULL;
 	    connp = connp->conn_next) {
 		/* We don't allow v4 fallback for v6 raw socket. */
-		if ((af == (connp->conn_af_isv6 ? IPV4_VERSION :
-		    IPV6_VERSION)) || (connp->conn_zoneid != zoneid)) {
+		if (af == (connp->conn_af_isv6 ? IPV4_VERSION :
+		    IPV6_VERSION))
 			continue;
-		}
 		if (connp->conn_fully_bound) {
 			if (af == IPV4_VERSION) {
-				if (IPCL_CONN_MATCH(connp, protocol,
-				    hdr->ipha_src, hdr->ipha_dst, ports)) {
-					break;
-				}
+				if (!IPCL_CONN_MATCH(connp, protocol,
+				    hdr->ipha_src, hdr->ipha_dst, ports))
+					continue;
 			} else {
-				if (IPCL_CONN_MATCH_V6(connp, protocol,
+				if (!IPCL_CONN_MATCH_V6(connp, protocol,
 				    ((ip6_t *)hdr)->ip6_src,
-				    ((ip6_t *)hdr)->ip6_dst, ports)) {
-					break;
-				}
+				    ((ip6_t *)hdr)->ip6_dst, ports))
+					continue;
 			}
 		} else {
 			if (af == IPV4_VERSION) {
-				if (IPCL_BIND_MATCH(connp, protocol,
-				    hdr->ipha_dst, lport)) {
-					break;
-				}
+				if (!IPCL_BIND_MATCH(connp, protocol,
+				    hdr->ipha_dst, lport))
+					continue;
 			} else {
-				if (IPCL_BIND_MATCH_V6(connp, protocol,
-				    ((ip6_t *)hdr)->ip6_dst, lport)) {
-					break;
-				}
+				if (!IPCL_BIND_MATCH_V6(connp, protocol,
+				    ((ip6_t *)hdr)->ip6_dst, lport))
+					continue;
 			}
 		}
+
+		if (connp->conn_zoneid == zoneid ||
+		    (unlabeled && connp->conn_mac_exempt))
+			break;
+	}
+	/*
+	 * If the connection is fully-bound and connection-oriented (TCP or
+	 * SCTP), then we've already validated the remote system's label.
+	 * There's no need to do it again for every packet.
+	 */
+	if (connp != NULL && is_system_labeled() && (!connp->conn_fully_bound ||
+	    !(connp->conn_flags & (IPCL_TCP|IPCL_SCTPCONN))) &&
+	    !tsol_receive_local(mp, dst, af, shared_addr, connp)) {
+		DTRACE_PROBE3(tx__ip__log__info__classify__rawip,
+		    char *, "connp(1) could not receive mp(2)",
+		    conn_t *, connp, mblk_t *, mp);
+		connp = NULL;
 	}
 
 	if (connp != NULL)
@@ -1797,7 +2138,8 @@
 }
 
 /*
- * To find a TCP listening connection matching the incoming segment.
+ * Finds a TCP/IPv4 listening connection; called by tcp_disconnect to locate
+ * a listener when changing state.
  */
 conn_t *
 ipcl_lookup_listener_v4(uint16_t lport, ipaddr_t laddr, zoneid_t zoneid)
@@ -1813,6 +2155,8 @@
 	if (laddr == 0)
 		return (NULL);
 
+	ASSERT(zoneid != ALL_ZONES);
+
 	bind_connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 	mutex_enter(&bind_connfp->connf_lock);
 	for (connp = bind_connfp->connf_head; connp != NULL;
@@ -1830,7 +2174,10 @@
 	return (NULL);
 }
 
-
+/*
+ * Finds a TCP/IPv6 listening connection; called by tcp_disconnect to locate
+ * a listener when changing state.
+ */
 conn_t *
 ipcl_lookup_listener_v6(uint16_t lport, in6_addr_t *laddr, uint_t ifindex,
     zoneid_t zoneid)
@@ -1846,6 +2193,7 @@
 	if (IN6_IS_ADDR_UNSPECIFIED(laddr))
 		return (NULL);
 
+	ASSERT(zoneid != ALL_ZONES);
 
 	bind_connfp = &ipcl_bind_fanout[IPCL_BIND_HASH(lport)];
 	mutex_enter(&bind_connfp->connf_lock);
--- a/usr/src/uts/common/inet/ip/ipsecah.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ipsecah.c	Fri Mar 24 12:29:20 2006 -0800
@@ -66,6 +66,7 @@
 #include <sys/crypto/common.h>
 #include <sys/crypto/api.h>
 #include <sys/kstat.h>
+#include <sys/strsubr.h>
 
 /* Packet dropper for AH drops. */
 static ipdropper_t ah_dropper;
@@ -4080,6 +4081,12 @@
 		nip6h->ip6_plen = htons((uint16_t)length);
 	}
 
+	if (is_system_labeled()) {
+		/*
+		 * inherit the label by setting it in the new ip header
+		 */
+		mblk_setcred(phdr_mp, DB_CRED(mp));
+	}
 	return (IPSEC_STATUS_SUCCESS);
 
 ah_in_discard:
@@ -4197,6 +4204,13 @@
 		nip6h->ip6_plen = htons((uint16_t)length);
 	}
 
+	if (is_system_labeled()) {
+		/*
+		 * inherit the label by setting it in the new ip header
+		 */
+		mblk_setcred(phdr_mp, DB_CRED(mp));
+	}
+
 	/* Skip the original IP header */
 	mp->b_rptr += hdrs_length;
 	if (mp->b_rptr == mp->b_wptr) {
--- a/usr/src/uts/common/inet/ip/nattymod.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/nattymod.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -308,7 +307,7 @@
 
 	ni->ni_addr = addr;
 
-	ire = ire_ctable_lookup(addr, 0, IRE_LOCAL, NULL, ALL_ZONES,
+	ire = ire_ctable_lookup(addr, 0, IRE_LOCAL, NULL, ALL_ZONES, NULL,
 	    MATCH_IRE_TYPE);
 	if (ire == NULL)
 		goto bail;
--- a/usr/src/uts/common/inet/ip/spd.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip/spd.c	Fri Mar 24 12:29:20 2006 -0800
@@ -3471,6 +3471,7 @@
 	attach_if = ii->ipsec_in_attach_if;
 	ifindex = ii->ipsec_in_ill_index;
 	zoneid = ii->ipsec_in_zoneid;
+	ASSERT(zoneid != ALL_ZONES);
 	v4 = ii->ipsec_in_v4;
 
 	ipsec_in_release_refs(ii);
@@ -4153,8 +4154,13 @@
 	 * When conn is non-NULL, the zoneid is set by ipsec_init_ipsec_out().
 	 * Otherwise set the zoneid based on the ire.
 	 */
-	if (connp == NULL)
-		io->ipsec_out_zoneid = ire->ire_zoneid;
+	if (connp == NULL) {
+		zoneid_t zoneid = ire->ire_zoneid;
+
+		if (zoneid == ALL_ZONES)
+			zoneid = GLOBAL_ZONEID;
+		io->ipsec_out_zoneid = zoneid;
+	}
 	return (ipsec_mp);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/ip/tn_ipopt.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,1469 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/disp.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/policy.h>
+#include <sys/tsol/label_macro.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/tcp.h>
+#include <inet/ipclassifier.h>
+#include <inet/ip_ire.h>
+
+/*
+ * This routine takes a sensitivity label as input and creates a CIPSO
+ * option in the specified buffer.  It returns the size of the CIPSO option.
+ * If the sensitivity label is too large for the CIPSO option, then 0
+ * is returned.
+ *
+ * tsol2cipso_tt1 returns 0 for failure and greater than 0 for success
+ * (more accurately, success means a return value between 10 and 40).
+ */
+
+static int
+tsol2cipso_tt1(const bslabel_t *sl, unsigned char *cop, uint32_t doi)
+{
+	struct cipso_tag_type_1 *tt1;
+	const _bslabel_impl_t *bsl;
+	const uchar_t *ucp;
+	int i;
+
+	if (doi == 0)
+		return (0);
+
+	/* check for Admin High sensitivity label */
+	if (blequal(sl, label2bslabel(l_admin_high)))
+		return (0);
+
+	/* check whether classification will fit in one octet */
+	bsl = (const _bslabel_impl_t *)sl;
+	if (LCLASS(bsl) & 0xFF00)
+		return (0);
+
+	/*
+	 * Check whether compartments will fit in 30 octets.
+	 * Compartments 241 - 256 are not allowed.
+	 */
+	if (ntohl(bsl->compartments.c8) & 0x0000FFFF)
+		return (0);
+
+	/*
+	 * Compute option length and tag length.
+	 * 'p' points to the last two bytes in the Sensitivity Label's
+	 * compartments; these cannot be mapped into CIPSO compartments.
+	 */
+	ucp = (const uchar_t *)&bsl->compartments.c8 + 2;
+	while (--ucp >= (const uchar_t *)&bsl->compartments.c1)
+		if (*ucp != 0)
+			break;
+
+	i =  ucp - (const uchar_t *)&bsl->compartments.c1 + 1;
+
+	if (cop == NULL)
+		return (10 + i);
+
+	doi = htonl(doi);
+	ucp = (const uchar_t *)&doi;
+	cop[IPOPT_OPTVAL] = IPOPT_COMSEC;
+	cop[IPOPT_OLEN] = 10 + i;
+	cop[IPOPT_OLEN+1] = ucp[0];
+	cop[IPOPT_OLEN+2] = ucp[1];
+	cop[IPOPT_OLEN+3] = ucp[2];
+	cop[IPOPT_OLEN+4] = ucp[3];
+	tt1 = (struct cipso_tag_type_1 *)&cop[IPOPT_OLEN + 5];
+	tt1->tag_type = 1;
+	tt1->tag_align = 0;
+	tt1->tag_sl = LCLASS(bsl);
+	tt1->tag_length = 4 + i;
+
+	bcopy(&bsl->compartments.c1, tt1->tag_cat, i);
+
+	return (cop[IPOPT_OLEN]);
+}
+
+/*
+ * The following routine copies a datagram's option into the specified buffer
+ * (if buffer pointer is non-null), or returns a pointer to the label within
+ * the streams message (if buffer is null).  In both cases, tsol_get_option
+ * returns the option's type.
+ *
+ * tsol_get_option assumes that the specified buffer is large enough to
+ * hold the largest valid CIPSO option.  Since the total number of
+ * IP header options cannot exceed 40 bytes, a 40 byte buffer is a good choice.
+ */
+
+tsol_ip_label_t
+tsol_get_option(mblk_t *mp, uchar_t **buffer)
+{
+	ipha_t	*ipha;
+	uchar_t	*opt;
+	uint32_t	totallen;
+	uint32_t	optval;
+	uint32_t	optlen;
+
+	ipha = (ipha_t *)mp->b_rptr;
+
+	/*
+	 * Get length (in 4 byte octets) of IP header options.
+	 * If header doesn't contain options, then return OPT_NONE.
+	 */
+	totallen = ipha->ipha_version_and_hdr_length -
+	    (uint8_t)((IP_VERSION << 4) + IP_SIMPLE_HDR_LENGTH_IN_WORDS);
+
+	if (totallen == 0)
+		return (OPT_NONE);
+
+	totallen <<= 2;
+
+	/*
+	 * Search for CIPSO option.
+	 * If no such option is present, then return OPT_NONE.
+	 */
+	opt = (uchar_t *)&ipha[1];
+	while (totallen != 0) {
+		switch (optval = opt[IPOPT_OPTVAL]) {
+		case IPOPT_EOL:
+			return (OPT_NONE);
+		case IPOPT_NOP:
+			optlen = 1;
+			break;
+		default:
+			if (totallen <= IPOPT_OLEN)
+				return (OPT_NONE);
+			optlen = opt[IPOPT_OLEN];
+			if (optlen < 2)
+				return (OPT_NONE);
+		}
+		if (optlen > totallen)
+			return (OPT_NONE);
+		/*
+		 * Copy pointer to option into '*buffer' and
+		 * return the option type.
+		 */
+		switch (optval) {
+		case IPOPT_COMSEC:
+			*buffer = opt;
+			if (TSOL_CIPSO_TAG_OFFSET < optlen &&
+			    opt[TSOL_CIPSO_TAG_OFFSET] == 1)
+				return (OPT_CIPSO);
+			return (OPT_NONE);
+		}
+		totallen -= optlen;
+		opt += optlen;
+	}
+	return (OPT_NONE);
+}
+
+/*
+ * tsol_compute_label()
+ *
+ * This routine computes the IP label that should be on a packet based on the
+ * connection and destination information.
+ *
+ * Returns:
+ *      0		Fetched label
+ *      EACCES		The packet failed the remote host accreditation
+ *      ENOMEM		Memory allocation failure
+ *	EINVAL		Label cannot be computed
+ */
+int
+tsol_compute_label(const cred_t *credp, ipaddr_t dst, uchar_t *opt_storage,
+    boolean_t isexempt)
+{
+	uint_t		sec_opt_len;
+	ts_label_t	*tsl;
+	tsol_tpc_t	*dst_rhtp;
+	ire_t		*ire, *sire = NULL;
+	boolean_t	compute_label = B_FALSE;
+	tsol_ire_gw_secattr_t *attrp;
+	zoneid_t	zoneid;
+
+	if (opt_storage != NULL)
+		opt_storage[IPOPT_OLEN] = 0;
+
+	if ((tsl = crgetlabel(credp)) == NULL)
+		return (0);
+
+	/* always pass multicast */
+	if (CLASSD(dst))
+		return (0);
+
+	if ((dst_rhtp = find_tpc(&dst, IPV4_VERSION, B_FALSE)) == NULL) {
+		DTRACE_PROBE3(tx__tnopt__log__info__labeling__lookupdst__v4,
+		    char *, "destination ip(1) not in database (with creds(2))",
+		    ipaddr_t, dst, cred_t *, credp);
+		return (EINVAL);
+	}
+
+	zoneid = crgetzoneid(credp);
+
+	switch (dst_rhtp->tpc_tp.host_type) {
+	case UNLABELED:
+		/*
+		 * Only add a label if the unlabeled destination is
+		 * not broadcast/local/loopback address, that it is
+		 * not on the same subnet, and that the next-hop
+		 * gateway is labeled.
+		 */
+		ire = ire_cache_lookup(dst, zoneid, tsl);
+
+		if (ire != NULL && (ire->ire_type & (IRE_BROADCAST | IRE_LOCAL |
+		    IRE_LOOPBACK | IRE_INTERFACE)) != 0) {
+			IRE_REFRELE(ire);
+			TPC_RELE(dst_rhtp);
+			return (0);
+		} else if (ire == NULL) {
+			ire = ire_ftable_lookup(dst, 0, 0, 0, NULL, &sire,
+			    zoneid, 0, tsl, (MATCH_IRE_RECURSIVE |
+			    MATCH_IRE_DEFAULT | MATCH_IRE_SECATTR));
+		}
+
+		/* no route to destination */
+		if (ire == NULL) {
+			DTRACE_PROBE4(
+			    tx__tnopt__log__info__labeling__routedst__v4,
+			    char *, "No route to unlabeled dest ip(1)/tpc(2) "
+			    "with creds(3).", ipaddr_t, dst, tsol_tpc_t *,
+			    dst_rhtp, cred_t *, credp);
+			TPC_RELE(dst_rhtp);
+			return (EINVAL);
+		}
+
+		/*
+		 * Prefix IRE from f-table lookup means that the destination
+		 * is not directly connected; check the next-hop attributes.
+		 */
+		if (sire != NULL) {
+			ASSERT(ire != NULL);
+			IRE_REFRELE(ire);
+			ire = sire;
+		}
+
+		attrp = ire->ire_gw_secattr;
+		if (attrp != NULL && attrp->igsa_rhc != NULL &&
+		    attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type != UNLABELED)
+			compute_label = B_TRUE;
+
+		/*
+		 * Can talk to unlabeled hosts if
+		 * (1) zone's label matches the default label, or
+		 * (2) SO_MAC_EXEMPT is on and we dominate the peer's label
+		 * (3) SO_MAC_EXEMPT is on and this is the global zone
+		 */
+		if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi ||
+		    (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
+		    &tsl->tsl_label) && (!isexempt ||
+		    (zoneid != GLOBAL_ZONEID && !bldominates(&tsl->tsl_label,
+		    &dst_rhtp->tpc_tp.tp_def_label))))) {
+			DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v4,
+			    char *, "unlabeled dest ip(1)/tpc(2) "
+			    "non-matching creds(3).", ipaddr_t, dst,
+			    tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+			IRE_REFRELE(ire);
+			TPC_RELE(dst_rhtp);
+			return (EACCES);
+		}
+
+		IRE_REFRELE(ire);
+		break;
+
+	case SUN_CIPSO:
+		/*
+		 * Can talk to labeled hosts if zone's label is within target's
+		 * label range or set.
+		 */
+		if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
+		    (!_blinrange(&tsl->tsl_label,
+		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
+		    !blinlset(&tsl->tsl_label,
+		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
+			DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v4,
+			    char *, "labeled dest ip(1)/tpc(2) "
+			    "non-matching creds(3).", ipaddr_t, dst,
+			    tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+			TPC_RELE(dst_rhtp);
+			return (EACCES);
+		}
+		compute_label = B_TRUE;
+		break;
+
+	default:
+		TPC_RELE(dst_rhtp);
+		return (EACCES);
+	}
+
+	if (!compute_label) {
+		TPC_RELE(dst_rhtp);
+		return (0);
+	}
+
+	/* compute the CIPSO option */
+	if (dst_rhtp->tpc_tp.host_type != UNLABELED)
+		sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
+		    tsl->tsl_doi);
+	else
+		sec_opt_len = tsol2cipso_tt1(&dst_rhtp->tpc_tp.tp_def_label,
+		    opt_storage, tsl->tsl_doi);
+	TPC_RELE(dst_rhtp);
+
+	if (sec_opt_len == 0) {
+		DTRACE_PROBE4(tx__tnopt__log__error__labeling__lostops__v4,
+		    char *,
+		    "options lack length for dest ip(1)/tpc(2) with creds(3).",
+		    ipaddr_t, dst, tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+/*
+ * Remove any existing security option (CIPSO) from the given IP
+ * header, move the 'buflen' bytes back to fill the gap, and return the number
+ * of bytes removed (as zero or negative number).  Assumes that the headers are
+ * sane.
+ */
+int
+tsol_remove_secopt(ipha_t *ipha, int buflen)
+{
+	int remlen, olen, oval, delta;
+	uchar_t *fptr, *tptr;
+	boolean_t noop_keep;
+
+	remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
+	fptr = tptr = (uchar_t *)(ipha + 1);
+	noop_keep = B_TRUE;
+	while (remlen > 0) {
+		oval = fptr[IPOPT_OPTVAL];
+
+		/* terminate on end of list */
+		if (oval == IPOPT_EOL)
+			break;
+
+		/*
+		 * Delete any no-ops following a deleted option, at least up
+		 * to a 4 octet alignment; copy others.
+		 */
+		if (oval == IPOPT_NOP) {
+			if (((fptr - (uchar_t *)ipha) & 3) == 0)
+				noop_keep = B_TRUE;
+			if (noop_keep)
+				*tptr++ = oval;
+			fptr++;
+			remlen--;
+			continue;
+		}
+
+		/* stop on corrupted list; just do nothing. */
+		if (remlen < 2)
+			return (0);
+		olen = fptr[IPOPT_OLEN];
+		if (olen < 2 || olen > remlen)
+			return (0);
+
+		/* skip over security options to delete them */
+		if (oval == IPOPT_COMSEC || oval == IPOPT_SECURITY) {
+			noop_keep = B_FALSE;
+			fptr += olen;
+			remlen -= olen;
+			continue;
+		}
+
+		/* copy the rest */
+		noop_keep = B_TRUE;
+		if (tptr != fptr)
+			ovbcopy(fptr, tptr, olen);
+		fptr += olen;
+		tptr += olen;
+		remlen -= olen;
+	}
+
+	fptr += remlen;
+
+	/* figure how much padding we'll need for header alignment */
+	olen = (tptr - (uchar_t *)ipha) & 3;
+	if (olen > 0) {
+		olen = 4 - olen;
+		/* pad with end-of-list */
+		bzero(tptr, olen);
+		tptr += olen;
+	}
+
+	/* slide back the headers that follow and update the IP header */
+	delta = fptr - tptr;
+	if (delta != 0) {
+		ovbcopy(fptr, tptr, ((uchar_t *)ipha + buflen) - fptr);
+		ipha->ipha_version_and_hdr_length -= delta / 4;
+	}
+	return (-delta);
+}
+
+/*
+ * Insert the option in 'optbuf' into the IP header pointed to by 'ipha', and
+ * move the data following the IP header (up to buflen) to accomodate the new
+ * option.  Assumes that up to IP_MAX_OPT_LENGTH bytes are available (in total)
+ * for IP options.  Returns the number of bytes actually inserted, or -1 if the
+ * option cannot be inserted.  (Note that negative return values are possible
+ * when noops must be compressed, and that only -1 indicates error.  Successful
+ * return value is always evenly divisible by 4, by definition.)
+ */
+int
+tsol_prepend_option(uchar_t *optbuf, ipha_t *ipha, int buflen)
+{
+	int remlen, padding, lastpad, totlen;
+	int oval, olen;
+	int delta;
+	uchar_t *optr;
+	uchar_t tempopt[IP_MAX_OPT_LENGTH], *toptr;
+
+	if (optbuf[IPOPT_OPTVAL] == IPOPT_EOL ||
+	    optbuf[IPOPT_OPTVAL] == IPOPT_NOP ||
+	    optbuf[IPOPT_OLEN] == 0)
+		return (0);
+
+	ASSERT(optbuf[IPOPT_OLEN] >= 2 &&
+	    optbuf[IPOPT_OLEN] <= IP_MAX_OPT_LENGTH);
+
+	/* first find the real (unpadded) length of the existing options */
+	remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
+	padding = totlen = lastpad = 0;
+	optr = (uchar_t *)(ipha + 1);
+	while (remlen > 0) {
+		oval = optr[IPOPT_OPTVAL];
+
+		/* stop at end of list */
+		if (oval == IPOPT_EOL)
+			break;
+
+		/* skip no-ops, noting that length byte isn't present */
+		if (oval == IPOPT_NOP) {
+			optr++;
+			padding++;
+			lastpad++;
+			totlen++;
+			remlen--;
+			continue;
+		}
+
+		/* give up on a corrupted list; report failure */
+		if (remlen < 2)
+			return (-1);
+		olen = optr[IPOPT_OLEN];
+		if (olen < 2 || olen > remlen)
+			return (-1);
+
+		lastpad = 0;
+		optr += olen;
+		totlen += olen;
+		remlen -= olen;
+	}
+
+	/* completely ignore any trailing padding */
+	totlen -= lastpad;
+	padding -= lastpad;
+
+	/*
+	 * If some sort of inter-option alignment was present, try to preserve
+	 * that alignment.  If alignment pushes us out past the maximum, then
+	 * discard it and try to compress to fit.  (We just "assume" that any
+	 * padding added was attempting to get 32 bit alignment.  If that's
+	 * wrong, that's just too bad.)
+	 */
+	if (padding > 0) {
+		olen = (optbuf[IPOPT_OLEN] + 3) & ~3;
+		if (olen + totlen > IP_MAX_OPT_LENGTH) {
+			totlen -= padding;
+			if (olen + totlen > IP_MAX_OPT_LENGTH)
+				return (-1);
+			padding = 0;
+		}
+	}
+
+	/*
+	 * Since we may need to compress or expand the option list, we write to
+	 * a temporary buffer and then copy the results back to the IP header.
+	 */
+	toptr = tempopt;
+
+	/* compute actual option to insert */
+	olen = optbuf[IPOPT_OLEN];
+	bcopy(optbuf, toptr, olen);
+	toptr += olen;
+	if (padding > 0) {
+		while ((olen & 3) != 0) {
+			*toptr++ = IPOPT_NOP;
+			olen++;
+		}
+	}
+
+	/* copy over the existing options */
+	optr = (uchar_t *)(ipha + 1);
+	while (totlen > 0) {
+		oval = optr[IPOPT_OPTVAL];
+
+		/* totlen doesn't include end-of-list marker */
+		ASSERT(oval != IPOPT_EOL);
+
+		/* handle no-ops; copy if desired, ignore otherwise */
+		if (oval == IPOPT_NOP) {
+			if (padding > 0) {
+				/* note: cannot overflow due to checks above */
+				ASSERT(toptr < tempopt + IP_MAX_OPT_LENGTH);
+				*toptr++ = oval;
+			}
+			optr++;
+			totlen--;
+			continue;
+		}
+
+		/* list cannot be corrupt at this point */
+		ASSERT(totlen >= 2);
+		olen = optr[IPOPT_OLEN];
+		ASSERT(olen >= 2 && olen <= totlen);
+
+		/* cannot run out of room due to tests above */
+		ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH);
+
+		bcopy(optr, toptr, olen);
+		optr += olen;
+		toptr += olen;
+		totlen -= olen;
+	}
+
+	/* figure how much padding we'll need for header alignment */
+	olen = (toptr - tempopt) & 3;
+	if (olen > 0) {
+		olen = 4 - olen;
+		ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH);
+		/* pad with end-of-list value */
+		bzero(toptr, olen);
+		toptr += olen;
+	}
+
+	/* move the headers as needed and update IP header */
+	olen = (toptr - tempopt) + IP_SIMPLE_HDR_LENGTH;
+	remlen = IPH_HDR_LENGTH(ipha);
+	delta = olen - remlen;
+	if (delta != 0) {
+		ovbcopy((uchar_t *)ipha + remlen, (uchar_t *)ipha + olen,
+		    buflen - remlen);
+		ipha->ipha_version_and_hdr_length += delta / 4;
+	}
+
+	/* slap in the new options */
+	bcopy(tempopt, ipha + 1, olen - IP_SIMPLE_HDR_LENGTH);
+
+	return (delta);
+}
+
+/*
+ * tsol_check_label()
+ *
+ * This routine computes the IP label that should be on the packet based on the
+ * connection and destination information.  If the label is there, it returns
+ * zero, so the caller knows that the label is syncronized, and further calls
+ * are not required.  If the label isn't right, then the right one is inserted.
+ *
+ * The packet's header is clear, before entering IPSec's engine.
+ *
+ * Returns:
+ *      0		Label on packet (was|is now) correct
+ *      EACCES		The packet failed the remote host accreditation.
+ *      ENOMEM		Memory allocation failure.
+ *	EINVAL		Label cannot be computed
+ */
+int
+tsol_check_label(const cred_t *credp, mblk_t **mpp, int *addedp,
+    boolean_t isexempt)
+{
+	mblk_t *mp = *mpp;
+	ipha_t  *ipha;
+	uchar_t opt_storage[IP_MAX_OPT_LENGTH];
+	uint_t hlen;
+	uint_t sec_opt_len;
+	uchar_t *optr;
+	int added;
+	int retv;
+
+	if (addedp != NULL)
+		*addedp = 0;
+
+	opt_storage[IPOPT_OPTVAL] = 0;
+
+	ipha = (ipha_t *)mp->b_rptr;
+
+	retv = tsol_compute_label(credp, ipha->ipha_dst, opt_storage, isexempt);
+	if (retv != 0)
+		return (retv);
+
+	optr = (uchar_t *)(ipha + 1);
+	hlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
+	sec_opt_len = opt_storage[IPOPT_OLEN];
+
+	if (hlen >= sec_opt_len) {
+		/* If no option is supposed to be there, make sure it's not */
+		if (sec_opt_len == 0 && hlen > 0 &&
+		    optr[IPOPT_OPTVAL] != IPOPT_COMSEC &&
+		    optr[IPOPT_OPTVAL] != IPOPT_SECURITY)
+			return (0);
+		/* if the option is there, it's always first */
+		if (sec_opt_len != 0 &&
+		    bcmp(opt_storage, optr, sec_opt_len) == 0)
+			return (0);
+	}
+
+	/*
+	 * If there is an option there, then it must be the wrong one; delete.
+	 */
+	if (hlen > 0)
+		mp->b_wptr += tsol_remove_secopt(ipha, MBLKL(mp));
+
+	/* Make sure we have room for the worst-case addition */
+	hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN];
+	hlen = (hlen + 3) & ~3;
+	if (hlen > IP_MAX_HDR_LENGTH)
+		hlen = IP_MAX_HDR_LENGTH;
+	hlen -= IPH_HDR_LENGTH(ipha);
+	if (mp->b_wptr + hlen > mp->b_datap->db_lim) {
+		int copylen;
+		mblk_t *new_mp;
+
+		/* allocate enough to be meaningful, but not *too* much */
+		copylen = MBLKL(mp);
+		if (copylen > 256)
+			copylen = 256;
+		new_mp = allocb(hlen + copylen +
+		    (mp->b_rptr - mp->b_datap->db_base), BPRI_HI);
+		if (new_mp == NULL)
+			return (ENOMEM);
+		mblk_setcred(new_mp, DB_CRED(mp));
+
+		/* keep the bias */
+		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+		new_mp->b_wptr = new_mp->b_rptr + copylen;
+		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+		new_mp->b_cont = mp;
+		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+			new_mp->b_cont = mp->b_cont;
+			freeb(mp);
+		}
+		*mpp = mp = new_mp;
+		ipha = (ipha_t *)mp->b_rptr;
+	}
+
+	added = tsol_prepend_option(opt_storage, ipha, MBLKL(mp));
+	if (added == -1)
+		goto param_prob;
+
+	if (addedp != NULL)
+		*addedp = added;
+
+	ASSERT((mp->b_wptr + added) <= DB_LIM(mp));
+	mp->b_wptr += added;
+
+	return (0);
+
+param_prob:
+	return (EINVAL);
+}
+
+/*
+ * IPv6 HopOpt extension header for the label option layout:
+ *	- One octet giving the type of the 'next extension header'
+ *	- Header extension length in 8-byte words, not including the
+ *	  1st 8 bytes, but including any pad bytes at the end.
+ *	  Eg. A value of 2 means 16 bytes not including the 1st 8 bytes.
+ *	- Followed by TLV encoded IPv6 label option. Option layout is
+ *		* One octet, IP6OPT_LS
+ *		* One octet option length in bytes of the option data following
+ *		  the length, but not including any pad bytes at the end.
+ *		* Four-octet DOI (IP6LS_DOI_V4)
+ *		* One octet suboption, IP6LS_TT_V4
+ *		* One octet suboption length in bytes of the suboption
+ *		  following the suboption length, including the suboption
+ *		  header length, but not including any pad bytes at the end.
+ *	- Pad to make the extension header a multiple of 8 bytes.
+ *
+ * This function returns the contents of 'IPv6 option structure' in the above.
+ * i.e starting from the IP6OPT_LS but not including the pad at the end.
+ * The user must prepend two octets (either padding or next header / length)
+ * and append padding out to the next 8 octet boundary.
+ */
+int
+tsol_compute_label_v6(const cred_t *credp, const in6_addr_t *dst,
+    uchar_t *opt_storage, boolean_t isexempt)
+{
+	tsol_tpc_t	*dst_rhtp;
+	ts_label_t	*tsl;
+	uint_t		sec_opt_len;
+	uint32_t	doi;
+	zoneid_t	zoneid;
+	ire_t		*ire, *sire;
+	tsol_ire_gw_secattr_t *attrp;
+	boolean_t	compute_label;
+
+	if (ip6opt_ls == 0)
+		return (EINVAL);
+
+	if (opt_storage != NULL)
+		opt_storage[IPOPT_OLEN] = 0;
+
+	if ((tsl = crgetlabel(credp)) == NULL)
+		return (0);
+
+	/* Always pass multicast */
+	if (IN6_IS_ADDR_MULTICAST(dst))
+		return (0);
+
+	if ((dst_rhtp = find_tpc(dst, IPV6_VERSION, B_FALSE)) == NULL) {
+		DTRACE_PROBE3(tx__tnopt__log__info__labeling__lookupdst__v6,
+		    char *, "destination ip6(1) not in database with creds(2)",
+		    in6_addr_t *, dst, cred_t *, credp);
+		return (EINVAL);
+	}
+
+	zoneid = crgetzoneid(credp);
+
+	/*
+	 * Fill in a V6 label.  If a new format is added here, make certain
+	 * that the maximum size of this label is reflected in sys/tsol/tnet.h
+	 * as TSOL_MAX_IPV6_OPTION.
+	 */
+	compute_label = B_FALSE;
+	switch (dst_rhtp->tpc_tp.host_type) {
+	case UNLABELED:
+		/*
+		 * Only add a label if the unlabeled destination is
+		 * not local or loopback address, that it is
+		 * not on the same subnet, and that the next-hop
+		 * gateway is labeled.
+		 */
+		sire = NULL;
+		ire = ire_cache_lookup_v6(dst, zoneid, tsl);
+
+		if (ire != NULL && (ire->ire_type & (IRE_LOCAL |
+		    IRE_LOOPBACK | IRE_INTERFACE)) != 0) {
+			IRE_REFRELE(ire);
+			TPC_RELE(dst_rhtp);
+			return (0);
+		} else if (ire == NULL) {
+			ire = ire_ftable_lookup_v6(dst, NULL, NULL, 0, NULL,
+			    &sire, zoneid, 0, tsl, (MATCH_IRE_RECURSIVE |
+			    MATCH_IRE_DEFAULT | MATCH_IRE_SECATTR));
+		}
+
+		/* no route to destination */
+		if (ire == NULL) {
+			DTRACE_PROBE4(
+			    tx__tnopt__log__info__labeling__routedst__v6,
+			    char *, "No route to unlabeled dest ip6(1)/tpc(2) "
+			    "with creds(3).", in6_addr_t *, dst, tsol_tpc_t *,
+			    dst_rhtp, cred_t *, credp);
+			TPC_RELE(dst_rhtp);
+			return (EINVAL);
+		}
+
+		/*
+		 * Prefix IRE from f-table lookup means that the destination
+		 * is not directly connected; check the next-hop attributes.
+		 */
+		if (sire != NULL) {
+			ASSERT(ire != NULL);
+			IRE_REFRELE(ire);
+			ire = sire;
+		}
+
+		attrp = ire->ire_gw_secattr;
+		if (attrp != NULL && attrp->igsa_rhc != NULL &&
+		    attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type != UNLABELED)
+			compute_label = B_TRUE;
+
+		if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi ||
+		    (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
+		    &tsl->tsl_label) && (!isexempt ||
+		    (zoneid != GLOBAL_ZONEID && !bldominates(&tsl->tsl_label,
+		    &dst_rhtp->tpc_tp.tp_def_label))))) {
+			DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v6,
+			    char *, "unlabeled dest ip6(1)/tpc(2) "
+			    "non-matching creds(3)", in6_addr_t *, dst,
+			    tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+			IRE_REFRELE(ire);
+			TPC_RELE(dst_rhtp);
+			return (EACCES);
+		}
+
+		IRE_REFRELE(ire);
+		break;
+
+	case SUN_CIPSO:
+		if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
+		    (!_blinrange(&tsl->tsl_label,
+		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
+		    !blinlset(&tsl->tsl_label,
+		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
+			DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v6,
+			    char *,
+			    "labeled dest ip6(1)/tpc(2) non-matching creds(3).",
+			    in6_addr_t *, dst, tsol_tpc_t *, dst_rhtp,
+			    cred_t *, credp);
+			TPC_RELE(dst_rhtp);
+			return (EACCES);
+		}
+		compute_label = B_TRUE;
+		break;
+
+	default:
+		TPC_RELE(dst_rhtp);
+		return (EACCES);
+	}
+
+	if (!compute_label) {
+		TPC_RELE(dst_rhtp);
+		return (0);
+	}
+
+	/* compute the CIPSO option */
+	if (opt_storage != NULL)
+		opt_storage += 8;
+	if (dst_rhtp->tpc_tp.host_type != UNLABELED) {
+		sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
+		    tsl->tsl_doi);
+	} else {
+		sec_opt_len = tsol2cipso_tt1(&dst_rhtp->tpc_tp.tp_def_label,
+		    opt_storage, tsl->tsl_doi);
+	}
+	TPC_RELE(dst_rhtp);
+
+	if (sec_opt_len == 0) {
+		DTRACE_PROBE4(tx__tnopt__log__error__labeling__lostops__v6,
+		    char *,
+		    "options lack length for dest ip6(1)/tpc(2) with creds(3).",
+		    in6_addr_t *, dst, tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+		return (EINVAL);
+	}
+
+	if (opt_storage == NULL)
+		return (0);
+
+	if (sec_opt_len < IP_MAX_OPT_LENGTH)
+		opt_storage[sec_opt_len] = IPOPT_EOL;
+
+	/*
+	 * Just in case the option length is odd, round it up to the next even
+	 * multiple.  The IPv6 option definition doesn't like odd numbers for
+	 * some reason.
+	 *
+	 * Length in the overall option header (IP6OPT_LS) does not include the
+	 * option header itself, but the length in the suboption does include
+	 * the suboption header.  Thus, when there's just one suboption, the
+	 * length in the option header is the suboption length plus 4 (for the
+	 * DOI value).
+	 */
+	opt_storage[-2] = IP6LS_TT_V4;
+	opt_storage[-1] = (sec_opt_len + 2 + 1) & ~1;
+	opt_storage[-8] = ip6opt_ls;
+	opt_storage[-7] = opt_storage[-1] + 4;
+	doi = htons(IP6LS_DOI_V4);
+	bcopy(&doi, opt_storage - 6, 4);
+
+	return (0);
+}
+
+/*
+ * Locate the start of the IP6OPT_LS label option and return it.
+ * Also return the start of the next non-pad option in after_secoptp.
+ * Usually the label option is the first option at least when packets
+ * are generated, but for generality we don't assume that on received packets.
+ */
+uchar_t *
+tsol_find_secopt_v6(
+    const uchar_t *ip6hbh,	/* Start of the hop-by-hop extension header */
+    uint_t hbhlen,		/* Length of the hop-by-hop extension header */
+    uchar_t **after_secoptp,	/* Non-pad option following the label option */
+    boolean_t *hbh_needed)	/* Is hop-by-hop hdr needed w/o label */
+{
+	uint_t	optlen;
+	uint_t	optused;
+	const uchar_t *optptr;
+	uchar_t	opt_type;
+	const uchar_t *secopt = NULL;
+
+	*hbh_needed = B_FALSE;
+	*after_secoptp = NULL;
+	optlen = hbhlen - 2;
+	optptr = ip6hbh + 2;
+	while (optlen != 0) {
+		opt_type = *optptr;
+		if (opt_type == IP6OPT_PAD1) {
+			optptr++;
+			optlen--;
+			continue;
+		}
+		if (optlen == 1)
+			break;
+		optused = 2 + optptr[1];
+		if (optused > optlen)
+			break;
+		/*
+		 * if we get here, ip6opt_ls can
+		 * not be 0 because it will always
+		 * match the IP6OPT_PAD1 above.
+		 * Therefore ip6opt_ls == 0 forces
+		 * this test to always fail here.
+		 */
+		if (opt_type == ip6opt_ls)
+			secopt = optptr;
+		else switch (opt_type) {
+		case IP6OPT_PADN:
+			break;
+		default:
+			/*
+			 * There is at least 1 option other than
+			 * the label option. So the hop-by-hop header is needed
+			 */
+			*hbh_needed = B_TRUE;
+			if (secopt != NULL) {
+				*after_secoptp = (uchar_t *)optptr;
+				return ((uchar_t *)secopt);
+			}
+			break;
+		}
+		optlen -= optused;
+		optptr += optused;
+	}
+	return ((uchar_t *)secopt);
+}
+
+/*
+ * Remove the label option from the hop-by-hop options header if it exists.
+ * 'buflen' is the total length of the packet typically b_wptr - b_rptr.
+ * Header and data following the label option that is deleted are copied
+ * (i.e. slid backward) to the right position.
+ */
+int
+tsol_remove_secopt_v6(ip6_t *ip6h, int buflen)
+{
+	uchar_t	*ip6hbh;	/* hop-by-hop header */
+	uint_t	hbhlen;		/* hop-by-hop extension header length */
+	uchar_t *secopt = NULL;
+	uchar_t *after_secopt;
+	uint_t	pad;
+	uint_t	delta;
+	boolean_t hbh_needed;
+
+	/*
+	 * hop-by-hop extension header must appear first, if it does not
+	 * exist, there is no label option.
+	 */
+	if (ip6h->ip6_nxt != IPPROTO_HOPOPTS)
+		return (0);
+
+	ip6hbh = (uchar_t *)&ip6h[1];
+	hbhlen = (ip6hbh[1] + 1) << 3;
+	/*
+	 * Locate the start of the label option if it exists and the end
+	 * of the label option including pads if any.
+	 */
+	secopt = tsol_find_secopt_v6(ip6hbh, hbhlen, &after_secopt,
+	    &hbh_needed);
+	if (secopt == NULL)
+		return (0);
+	if (!hbh_needed) {
+		uchar_t	next_hdr;
+		/*
+		 * The label option was the only option in the hop-by-hop
+		 * header. We don't need the hop-by-hop header itself any
+		 * longer.
+		 */
+		next_hdr = ip6hbh[0];
+		ovbcopy(ip6hbh + hbhlen, ip6hbh,
+		    buflen - (IPV6_HDR_LEN + hbhlen));
+		ip6h->ip6_plen -= hbhlen;
+		ip6h->ip6_nxt = next_hdr;
+		return (hbhlen);
+	}
+
+	if (after_secopt == NULL) {
+		/* There is no option following the label option */
+		after_secopt = ip6hbh + hbhlen;
+	}
+
+	/*
+	 * After deleting the label option, we need to slide the headers
+	 * and data back, while still maintaining the same alignment (module 8)
+	 * for the other options. So we slide the headers and data back only
+	 * by an integral multiple of 8 bytes, and fill the remaining bytes
+	 * with pads.
+	 */
+	delta = after_secopt - secopt;
+	pad = delta % 8;
+	if (pad == 1) {
+		secopt[0] = IP6OPT_PAD1;
+	} else if (pad > 1) {
+		secopt[0] = IP6OPT_PADN;
+		secopt[1] = pad - 2;
+		if (pad > 2)
+			bzero(&secopt[2], pad - 2);
+	}
+	secopt += pad;
+	delta -= pad;
+	ovbcopy(after_secopt, secopt,
+	    (uchar_t *)ip6h + buflen - after_secopt);
+	ip6hbh[1] -= delta/8;
+	ip6h->ip6_plen -= delta;
+
+	return (delta);
+}
+
+/*
+ * 'optbuf' contains a CIPSO label embedded in an IPv6 hop-by-hop option,
+ * starting with the IP6OPT_LS option type. The format of this hop-by-hop
+ * option is described in the block comment above tsol_compute_label_v6.
+ * This function prepends this hop-by-hop option before any other hop-by-hop
+ * options in the hop-by-hop header if one already exists, else a new
+ * hop-by-hop header is created and stuffed into the packet following
+ * the IPv6 header. 'buflen' is the total length of the packet i.e.
+ * b_wptr - b_rptr. The caller ensures that there is enough space for the
+ * extra option being added. Header and data following the position where
+ * the label option is inserted are copied (i.e. slid forward) to the right
+ * position.
+ */
+int
+tsol_prepend_option_v6(uchar_t *optbuf, ip6_t *ip6h, int buflen)
+{
+	/*
+	 * rawlen is the length of the label option in bytes, not including
+	 * any pads, starting from the IP6OPT_LS (option type) byte.
+	 */
+	uint_t	rawlen;
+
+	uint_t	optlen;		/* rawlen rounded to an 8 byte multiple */
+	uchar_t	*ip6hbh;	/* start of the hop-by-hop extension header */
+	uint_t	hbhlen;		/* Length of the hop-by-hop extension header */
+	uint_t	pad_len;
+	uchar_t	*pad_position;
+	int	delta;		/* Actual number of bytes inserted */
+
+	rawlen = optbuf[1] + 2;	/* Add 2 for the option type, option length */
+	ip6hbh = (uchar_t *)&ip6h[1];
+	if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
+		/*
+		 * There is a hop-by-hop header present already. In order to
+		 * preserve the alignment of the other options at the existing
+		 * value (modulo 8) we need to pad the label option to a
+		 * multiple of 8 bytes before prepending it to the other
+		 * options. Slide the extension headers and data forward to
+		 * accomodate the label option at the start of the hop-by-hop
+		 * header
+		 */
+		delta = optlen = (rawlen + 7) & ~7;
+		pad_len = optlen - rawlen;
+		pad_position = ip6hbh + 2 + rawlen;
+		ovbcopy(ip6hbh + 2, ip6hbh + 2 + optlen,
+		    buflen - (IPV6_HDR_LEN + 2));
+		/*
+		 * Bump up the hop-by-hop extension header length by
+		 * the number of 8-byte words added
+		 */
+		optlen >>= 3;
+		if (ip6hbh[1] + optlen > 255)
+			return (-1);
+		ip6hbh[1] += optlen;
+	} else {
+		/*
+		 * There is no hop-by-hop header in the packet. Construct a
+		 * new Hop-by-hop extension header (a multiple of 8 bytes).
+		 * Slide any other extension headers and data forward to
+		 * accomodate this hop-by-hop header
+		 */
+		delta = hbhlen = (2 + rawlen + 7) & ~7; /* +2 for nxthdr, len */
+		pad_len = hbhlen - (2 + rawlen);
+		pad_position = ip6hbh + 2 + rawlen;
+		ovbcopy(ip6hbh, ip6hbh + hbhlen, buflen - IPV6_HDR_LEN);
+		ip6hbh[0] = ip6h->ip6_nxt;
+		/*
+		 * hop-by-hop extension header length in 8-byte words, not
+		 * including the 1st 8 bytes of the hop-by-hop header.
+		 */
+		ip6hbh[1] = (hbhlen >> 3) - 1;
+		ip6h->ip6_nxt = IPPROTO_HOPOPTS;
+	}
+	/*
+	 * Copy the label option into the hop-by-hop header and insert any
+	 * needed pads
+	 */
+	bcopy(optbuf, ip6hbh + 2, rawlen);
+	if (pad_len == 1) {
+		pad_position[0] = IP6OPT_PAD1;
+	} else if (pad_len > 1) {
+		pad_position[0] = IP6OPT_PADN;
+		pad_position[1] = pad_len - 2;
+		if (pad_len > 2)
+			bzero(pad_position + 2, pad_len - 2);
+	}
+	ip6h->ip6_plen += delta;
+	return (delta);
+}
+
+/*
+ * tsol_check_label_v6()
+ *
+ * This routine computes the IP label that should be on the packet based on the
+ * connection and destination information.  It's called only by the IP
+ * forwarding logic, because all internal modules atop IP know how to generate
+ * their own labels.
+ *
+ * Returns:
+ *      0		Label on packet was already correct
+ *      EACCESS		The packet failed the remote host accreditation.
+ *      ENOMEM		Memory allocation failure.
+ */
+int
+tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, int *addedp,
+    boolean_t isexempt)
+{
+	mblk_t *mp = *mpp;
+	ip6_t  *ip6h;
+	/*
+	 * Label option length is limited to IP_MAX_OPT_LENGTH for
+	 * symmetry with IPv4. Can be relaxed if needed
+	 */
+	uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
+	uint_t hlen;
+	uint_t sec_opt_len; /* label option length not including type, len */
+	int added;
+	int retv;
+	uchar_t	*after_secopt;
+	uchar_t	*secopt = NULL;
+	uchar_t	*ip6hbh;
+	uint_t	hbhlen;
+	boolean_t hbh_needed;
+
+	if (addedp != NULL)
+		*addedp = 0;
+
+	ip6h = (ip6_t *)mp->b_rptr;
+	retv = tsol_compute_label_v6(credp, &ip6h->ip6_dst, opt_storage,
+	    isexempt);
+	if (retv != 0)
+		return (retv);
+
+	sec_opt_len = opt_storage[1];
+
+	if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
+		ip6hbh = (uchar_t *)&ip6h[1];
+		hbhlen = (ip6hbh[1] + 1) << 3;
+		secopt = tsol_find_secopt_v6(ip6hbh, hbhlen, &after_secopt,
+		    &hbh_needed);
+	}
+
+	if (sec_opt_len == 0 && secopt == NULL) {
+		/*
+		 * The packet is not supposed to have a label, and it
+		 * does not have one currently
+		 */
+		return (0);
+	}
+	if (secopt != NULL && sec_opt_len != 0 &&
+	    (bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) {
+		/* The packet has the correct label already */
+		return (0);
+	}
+
+	/*
+	 * If there is an option there, then it must be the wrong one; delete.
+	 */
+	if (secopt != NULL)
+		mp->b_wptr += tsol_remove_secopt_v6(ip6h, MBLKL(mp));
+
+	/*
+	 * Make sure we have room for the worst-case addition. Add 2 bytes for
+	 * the hop-by-hop ext header's next header and length fields. Add
+	 * another 2 bytes for the label option type, len and then round
+	 * up to the next 8-byte multiple.
+	 */
+	hlen = (4 + sec_opt_len + 7) & ~7;
+	if (mp->b_wptr + hlen > mp->b_datap->db_lim) {
+		int copylen;
+		mblk_t *new_mp;
+		uint16_t hdr_len;
+
+		hdr_len = ip_hdr_length_v6(mp, ip6h);
+		/*
+		 * Allocate enough to be meaningful, but not *too* much.
+		 * Also all the IPv6 extension headers must be in the same mblk
+		 */
+		copylen = MBLKL(mp);
+		if (copylen > 256)
+			copylen = 256;
+		if (copylen < hdr_len)
+			copylen = hdr_len;
+		new_mp = allocb(hlen + copylen +
+		    (mp->b_rptr - mp->b_datap->db_base), BPRI_HI);
+		if (new_mp == NULL)
+			return (ENOMEM);
+
+		/* keep the bias */
+		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+		new_mp->b_wptr = new_mp->b_rptr + copylen;
+		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+		new_mp->b_cont = mp;
+		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+			new_mp->b_cont = mp->b_cont;
+			freeb(mp);
+		}
+		*mpp = mp = new_mp;
+		ip6h = (ip6_t *)mp->b_rptr;
+	}
+
+	added = tsol_prepend_option_v6(opt_storage, ip6h, MBLKL(mp));
+	if (added == -1)
+		goto param_prob;
+
+	if (addedp != NULL)
+		*addedp = added;
+
+	ASSERT(mp->b_wptr + added <= DB_LIM(mp));
+	mp->b_wptr += added;
+
+	return (0);
+
+param_prob:
+	return (EINVAL);
+}
+
+/*
+ * Update the given IPv6 "sticky options" structure to contain the provided
+ * label, which is encoded as an IPv6 option.  Existing label is removed if
+ * necessary, and storage is allocated/freed/resized.
+ *
+ * Returns 0 on success, errno on failure.
+ */
+int
+tsol_update_sticky(ip6_pkt_t *ipp, uint_t *labellen, const uchar_t *labelopt)
+{
+	int rawlen, optlen, newlen;
+	uchar_t *newopts;
+
+	/*
+	 * rawlen is the size of the IPv6 label to be inserted from labelopt.
+	 * optlen is the total length of that option, including any necessary
+	 * headers and padding.  newlen is the new size of the total hop-by-hop
+	 * options buffer, including user options.
+	 */
+	if ((rawlen = labelopt[1]) != 0) {
+		rawlen += 2;	/* add in header size */
+		optlen = (2 + rawlen + 7) & ~7;
+	} else {
+		optlen = 0;
+	}
+	newlen = ipp->ipp_hopoptslen + optlen - *labellen;
+	if (optlen > *labellen) {
+		if (newlen > IP6_MAX_OPT_LENGTH)
+			return (EHOSTUNREACH);
+		/* If the label is bigger than last time, then reallocate */
+		newopts = kmem_alloc(newlen, KM_NOSLEEP);
+		if (newopts == NULL)
+			return (ENOMEM);
+		/*
+		 * If the user has hop-by-hop stickyoptions set, then copy his
+		 * options in after the security label.
+		 */
+		if (ipp->ipp_hopoptslen > *labellen) {
+			bcopy(ipp->ipp_hopopts + *labellen, newopts + optlen,
+			    ipp->ipp_hopoptslen - *labellen);
+			/*
+			 * Stomp out any header gunk here - this was the
+			 * previous next-header and option length field.
+			 */
+			newopts[optlen] = IP6OPT_PADN;
+			newopts[optlen + 1] = 0;
+		}
+		if (ipp->ipp_hopopts != NULL)
+			kmem_free(ipp->ipp_hopopts, ipp->ipp_hopoptslen);
+		ipp->ipp_hopopts = (ip6_hbh_t *)newopts;
+	} else if (optlen < *labellen) {
+		/* If the label got smaller, then adjust downward. */
+		if (newlen == 0 && ipp->ipp_hopopts != NULL) {
+			kmem_free(ipp->ipp_hopopts, ipp->ipp_hopoptslen);
+			ipp->ipp_hopopts = NULL;
+			ipp->ipp_fields &= ~IPPF_HOPOPTS;
+		}
+		/* If the user still has options, move those back. */
+		if (ipp->ipp_hopoptslen > *labellen) {
+			ovbcopy(ipp->ipp_hopopts + *labellen,
+			    ipp->ipp_hopopts + optlen,
+			    ipp->ipp_hopoptslen - *labellen);
+		}
+	}
+	ipp->ipp_hopoptslen = newlen;
+	*labellen = optlen;
+
+	newopts = (uchar_t *)ipp->ipp_hopopts;
+
+	/* If there are any options, then fix up reported length */
+	if (newlen > 0) {
+		newopts[1] = (newlen + 7) / 8 - 1;
+		ipp->ipp_fields |= IPPF_HOPOPTS;
+	}
+
+	/* If there's a label, then insert it now */
+	if (optlen > 0) {
+		/* skip next-header and length fields */
+		newopts += 2;
+		bcopy(labelopt, newopts, rawlen);
+		newopts += rawlen;
+		/* make sure padding comes out right */
+		optlen -= 2 + rawlen;
+		if (optlen == 1) {
+			newopts[0] = IP6OPT_PAD1;
+		} else if (optlen > 1) {
+			newopts[0] = IP6OPT_PADN;
+			optlen -=  2;
+			newopts[1] = optlen;
+			if (optlen > 0)
+				bzero(newopts + 2, optlen);
+		}
+	}
+	return (0);
+}
+
+int
+tsol_update_options(uchar_t **opts, uint_t *totlen, uint_t *labellen,
+    const uchar_t *labelopt)
+{
+	int optlen, newlen;
+	uchar_t *newopts;
+
+	optlen = (labelopt[IPOPT_OLEN] + 3) & ~3;
+	newlen = *totlen + optlen - *labellen;
+	if (optlen > *labellen) {
+		if (newlen > IP_MAX_OPT_LENGTH)
+			return (EHOSTUNREACH);
+		newopts = (uchar_t *)mi_alloc(newlen, BPRI_HI);
+		if (newopts == NULL)
+			return (ENOMEM);
+		if (*totlen > *labellen) {
+			bcopy(*opts + *labellen, newopts + optlen,
+			    *totlen - *labellen);
+		}
+		if (*opts != NULL)
+			mi_free((char *)*opts);
+		*opts = newopts;
+	} else if (optlen < *labellen) {
+		if (newlen == 0 && *opts != NULL) {
+			mi_free((char *)*opts);
+			*opts = NULL;
+		}
+		if (*totlen > *labellen) {
+			ovbcopy(*opts + *labellen, *opts + optlen,
+			    *totlen - *labellen);
+		}
+	}
+	*totlen = newlen;
+	*labellen = optlen;
+	if (optlen > 0) {
+		newopts = *opts;
+		bcopy(labelopt, newopts, optlen);
+		/* check if there are user-supplied options that follow */
+		if (optlen < newlen) {
+			/* compute amount of embedded alignment needed */
+			optlen -= newopts[IPOPT_OLEN];
+			newopts += newopts[IPOPT_OLEN];
+			while (--optlen >= 0)
+				*newopts++ = IPOPT_NOP;
+		} else if (optlen != newopts[IPOPT_OLEN]) {
+			/*
+			 * The label option is the only option and it is
+			 * not a multiple of 4 bytes.
+			 */
+			optlen -= newopts[IPOPT_OLEN];
+			newopts += newopts[IPOPT_OLEN];
+			while (--optlen >= 0)
+				*newopts++ = IPOPT_EOL;
+		}
+	}
+	return (0);
+}
+
+/*
+ * This does the bulk of the processing for setting IPPROTO_IP {T_,}IP_OPTIONS.
+ */
+boolean_t
+tsol_option_set(uchar_t **opts, uint_t *optlen, uint_t labellen,
+    const uchar_t *useropts, uint_t userlen)
+{
+	int newlen;
+	uchar_t *newopts;
+
+	newlen = userlen + labellen;
+	if (newlen > *optlen) {
+		/* need more room */
+		newopts = (uchar_t *)mi_alloc(newlen, BPRI_HI);
+		if (newopts == NULL)
+			return (ENOMEM);
+		/*
+		 * The supplied *opts can't be NULL in this case,
+		 * since there's an existing label.
+		 */
+		if (labellen > 0)
+			bcopy(*opts, newopts, labellen);
+		if (*opts != NULL)
+			mi_free((char *)*opts);
+		*opts = newopts;
+	}
+
+	if (newlen == 0) {
+		/* special case -- no remaining IP options at all */
+		if (*opts != NULL) {
+			mi_free((char *)*opts);
+			*opts = NULL;
+		}
+	} else if (userlen > 0) {
+		/* merge in the user's options */
+		newopts = *opts;
+		if (labellen > 0) {
+			int extra = labellen - newopts[IPOPT_OLEN];
+
+			newopts += newopts[IPOPT_OLEN];
+			while (--extra >= 0)
+				*newopts++ = IPOPT_NOP;
+		}
+		bcopy(useropts, newopts, userlen);
+	}
+
+	*optlen = newlen;
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/ip/tnet.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,2025 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/stropts.h>
+#include <sys/sunddi.h>
+#include <sys/cred.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/errno.h>
+#include <sys/disp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <inet/common.h>
+#include <inet/ipclassifier.h>
+#include <inet/ip.h>
+#include <inet/mib2.h>
+#include <inet/nd.h>
+#include <inet/tcp.h>
+#include <inet/ip_rts.h>
+#include <inet/ip_ire.h>
+#include <inet/ip_if.h>
+#include <sys/modhash.h>
+
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
+#include <sys/tsol/tnet.h>
+#include <sys/tsol/tndb.h>
+#include <sys/strsun.h>
+
+/* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */
+int tsol_strict_error;
+
+/*
+ * Some notes on the Trusted Solaris IRE gateway security attributes:
+ *
+ * When running in Trusted mode, the routing subsystem determines whether or
+ * not a packet can be delivered to an off-link host (not directly reachable
+ * through an interface) based on the accreditation checks of the packet's
+ * security attributes against those associated with the next-hop gateway.
+ *
+ * The next-hop gateway's security attributes can be derived from two sources
+ * (in order of preference): route-related and the host database.  A Trusted
+ * system must be configured with at least the host database containing an
+ * entry for the next-hop gateway, or otherwise no accreditation checks can
+ * be performed, which may result in the inability to send packets to any
+ * off-link destination host.
+ *
+ * The major differences between the two sources are the number and type of
+ * security attributes used for accreditation checks.  A host database entry
+ * can contain at most one set of security attributes, specific only to the
+ * next-hop gateway.  On contrast, route-related security attributes are made
+ * up of a collection of security attributes for the distant networks, and
+ * are grouped together per next-hop gateway used to reach those networks.
+ * This is the preferred method, and the routing subsystem will fallback to
+ * the host database entry only if there are no route-related attributes
+ * associated with the next-hop gateway.
+ *
+ * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/
+ * INTERFACE type) are initialized to contain a placeholder to store this
+ * information.  The ire_gw_secattr structure gets allocated, initialized
+ * and associated with the IRE during the time of the IRE creation.  The
+ * initialization process also includes resolving the host database entry
+ * of the next-hop gateway for fallback purposes.  It does not include any
+ * route-related attribute setup, as that process comes separately as part
+ * of the route requests (add/change) made to the routing subsystem.
+ *
+ * The underlying logic which involves associating IREs with the gateway
+ * security attributes are represented by the following data structures:
+ *
+ * tsol_gcdb_t, or "gcdb"
+ *
+ *	- This is a system-wide collection of records containing the
+ *	  currently used route-related security attributes, which are fed
+ *	  through the routing socket interface, e.g. "route add/change".
+ *
+ * tsol_gc_t, or "gc"
+ *
+ *	- This is the gateway credential structure, and it provides for the
+ *	  only mechanism to access the contents of gcdb.  More than one gc
+ *	  entries may refer to the same gcdb record.  gc's in the system are
+ *	  grouped according to the next-hop gateway address.
+ *
+ * tsol_gcgrp_t, or "gcgrp"
+ *
+ *	- Group of gateway credentials, and is unique per next-hop gateway
+ *	  address.  When the group is not empty, i.e. when gcgrp_count is
+ *	  greater than zero, it contains one or more gc's, each pointing to
+ *	  a gcdb record which indicates the gateway security attributes
+ *	  associated with the next-hop gateway.
+ *
+ * The fields of the tsol_ire_gw_secattr_t used from within the IRE are:
+ *
+ * igsa_lock
+ *
+ *	- Lock that protects all fields within tsol_ire_gw_secattr_t.
+ *
+ * igsa_rhc
+ *
+ *	- Remote host cache database entry of next-hop gateway.  This is
+ *	  used in the case when there are no route-related attributes
+ *	  configured for the IRE.
+ *
+ * igsa_gc
+ *
+ *	- A set of route-related attributes that only get set for prefix
+ *	  IREs.  If this is non-NULL, the prefix IRE has been associated
+ *	  with a set of gateway security attributes by way of route add/
+ *	  change functionality.  This field stays NULL for IRE_CACHEs.
+ *
+ * igsa_gcgrp
+ *
+ *	- Group of gc's which only gets set for IRE_CACHEs.  Each of the gc
+ *	  points to a gcdb record that contains the security attributes
+ *	  used to perform the credential checks of the packet which uses
+ *	  the IRE.  If the group is not empty, the list of gc's can be
+ *	  traversed starting at gcgrp_head.  This field stays NULL for
+ *	  prefix IREs.
+ */
+
+static kmem_cache_t *ire_gw_secattr_cache;
+
+#define	GCDB_HASH_SIZE	101
+#define	GCGRP_HASH_SIZE	101
+
+#define	GCDB_REFRELE(p) {		\
+	mutex_enter(&gcdb_lock);	\
+	ASSERT((p)->gcdb_refcnt > 0);	\
+	if (--((p)->gcdb_refcnt) == 0)	\
+		gcdb_inactive(p);	\
+	ASSERT(MUTEX_HELD(&gcdb_lock));	\
+	mutex_exit(&gcdb_lock);		\
+}
+
+static int gcdb_hash_size = GCDB_HASH_SIZE;
+static int gcgrp_hash_size = GCGRP_HASH_SIZE;
+static mod_hash_t *gcdb_hash;
+static mod_hash_t *gcgrp4_hash;
+static mod_hash_t *gcgrp6_hash;
+
+static kmutex_t gcdb_lock;
+kmutex_t gcgrp_lock;
+
+static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t);
+static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t);
+static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t);
+static void gcdb_inactive(tsol_gcdb_t *);
+
+static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t);
+static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t);
+
+static int ire_gw_secattr_constructor(void *, void *, int);
+static void ire_gw_secattr_destructor(void *, void *);
+
+void
+tnet_init(void)
+{
+	ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache",
+	    sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor,
+	    ire_gw_secattr_destructor, NULL, NULL, NULL, 0);
+
+	gcdb_hash = mod_hash_create_extended("gcdb_hash",
+	    gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
+	    gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP);
+
+	gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash",
+	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
+	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
+
+	gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash",
+	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
+	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
+
+	mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+void
+tnet_fini(void)
+{
+	kmem_cache_destroy(ire_gw_secattr_cache);
+	mod_hash_destroy_hash(gcdb_hash);
+	mod_hash_destroy_hash(gcgrp4_hash);
+	mod_hash_destroy_hash(gcgrp6_hash);
+	mutex_destroy(&gcdb_lock);
+	mutex_destroy(&gcgrp_lock);
+}
+
+/* ARGSUSED */
+static int
+ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags)
+{
+	tsol_ire_gw_secattr_t *attrp = buf;
+
+	mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	attrp->igsa_rhc = NULL;
+	attrp->igsa_gc = NULL;
+	attrp->igsa_gcgrp = NULL;
+
+	return (0);
+}
+
+/* ARGSUSED */
+static void
+ire_gw_secattr_destructor(void *buf, void *cdrarg)
+{
+	tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf;
+
+	mutex_destroy(&attrp->igsa_lock);
+}
+
+tsol_ire_gw_secattr_t *
+ire_gw_secattr_alloc(int kmflags)
+{
+	return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags));
+}
+
+void
+ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp)
+{
+	ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock));
+
+	if (attrp->igsa_rhc != NULL) {
+		TNRHC_RELE(attrp->igsa_rhc);
+		attrp->igsa_rhc = NULL;
+	}
+
+	if (attrp->igsa_gc != NULL) {
+		GC_REFRELE(attrp->igsa_gc);
+		attrp->igsa_gc = NULL;
+	}
+	if (attrp->igsa_gcgrp != NULL) {
+		GCGRP_REFRELE(attrp->igsa_gcgrp);
+		attrp->igsa_gcgrp = NULL;
+	}
+
+	ASSERT(attrp->igsa_rhc == NULL);
+	ASSERT(attrp->igsa_gc == NULL);
+	ASSERT(attrp->igsa_gcgrp == NULL);
+
+	kmem_cache_free(ire_gw_secattr_cache, attrp);
+}
+
+/* ARGSUSED */
+static uint_t
+gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key)
+{
+	const struct rtsa_s *rp = (struct rtsa_s *)key;
+	const uint32_t *up, *ue;
+	uint_t hash;
+	int i;
+
+	ASSERT(rp != NULL);
+
+	/* See comments in hash_bylabel in zone.c for details */
+	hash = rp->rtsa_doi + (rp->rtsa_doi << 1);
+	up = (const uint32_t *)&rp->rtsa_slrange;
+	ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up);
+	i = 1;
+	while (up < ue) {
+		/* using 2^n + 1, 1 <= n <= 16 as source of many primes */
+		hash += *up + (*up << ((i % 16) + 1));
+		up++;
+		i++;
+	}
+	return (hash);
+}
+
+static int
+gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+	struct rtsa_s *rp1 = (struct rtsa_s *)key1;
+	struct rtsa_s *rp2 = (struct rtsa_s *)key2;
+
+	ASSERT(rp1 != NULL && rp2 != NULL);
+
+	if (blequal(&rp1->rtsa_slrange.lower_bound,
+	    &rp2->rtsa_slrange.lower_bound) &&
+	    blequal(&rp1->rtsa_slrange.upper_bound,
+	    &rp2->rtsa_slrange.upper_bound) &&
+	    rp1->rtsa_doi == rp2->rtsa_doi)
+		return (0);
+
+	/* No match; not found */
+	return (-1);
+}
+
+/* ARGSUSED */
+static uint_t
+gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key)
+{
+	tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key;
+	uint_t		idx = 0;
+	uint32_t	*ap;
+
+	ASSERT(ga != NULL);
+	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
+
+	ap = (uint32_t *)&ga->ga_addr.s6_addr32[0];
+	idx ^= *ap++;
+	idx ^= *ap++;
+	idx ^= *ap++;
+	idx ^= *ap;
+
+	return (idx);
+}
+
+static int
+gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+	tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1;
+	tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2;
+
+	ASSERT(ga1 != NULL && ga2 != NULL);
+
+	/* Address family must match */
+	if (ga1->ga_af != ga2->ga_af)
+		return (-1);
+
+	if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] &&
+	    ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] &&
+	    ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] &&
+	    ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3])
+		return (0);
+
+	/* No match; not found */
+	return (-1);
+}
+
+#define	RTSAFLAGS	"\20\11cipso\3doi\2max_sl\1min_sl"
+
+int
+rtsa_validate(const struct rtsa_s *rp)
+{
+	uint32_t mask = rp->rtsa_mask;
+
+	/* RTSA_CIPSO must be set, and DOI must not be zero */
+	if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) {
+		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
+		    "rtsa(1) lacks flag or has 0 doi.",
+		    rtsa_s *, rp);
+		return (EINVAL);
+	}
+	/*
+	 * SL range must be specified, and it must have its
+	 * upper bound dominating its lower bound.
+	 */
+	if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE ||
+	    !bldominates(&rp->rtsa_slrange.upper_bound,
+	    &rp->rtsa_slrange.lower_bound)) {
+		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
+		    "rtsa(1) min_sl and max_sl not set or max_sl is "
+		    "not dominating.", rtsa_s *, rp);
+		return (EINVAL);
+	}
+	return (0);
+}
+
+/*
+ * A brief explanation of the reference counting scheme:
+ *
+ * Prefix IREs have a non-NULL igsa_gc and a NULL igsa_gcgrp;
+ * IRE_CACHEs have it vice-versa.
+ *
+ * Apart from dynamic references due to to reference holds done
+ * actively by threads, we have the following references:
+ *
+ * gcdb_refcnt:
+ *	- Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference
+ *	  to the gcdb_refcnt.
+ *
+ * gc_refcnt:
+ *	- A prefix IRE that points to an igsa_gc contributes a reference
+ *	  to the gc_refcnt.
+ *
+ * gcgrp_refcnt:
+ *	- An IRE_CACHE that points to an igsa_gcgrp contributes a reference
+ *	  to the gcgrp_refcnt of the associated tsol_gcgrp_t.
+ *	- Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes
+ *	  a reference to the gcgrp_refcnt.
+ */
+static tsol_gcdb_t *
+gcdb_lookup(struct rtsa_s *rp, boolean_t alloc)
+{
+	tsol_gcdb_t *gcdb = NULL;
+
+	if (rtsa_validate(rp) != 0)
+		return (NULL);
+
+	mutex_enter(&gcdb_lock);
+	/* Find a copy in the cache; otherwise, create one and cache it */
+	if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp,
+	    (mod_hash_val_t *)&gcdb) == 0) {
+		gcdb->gcdb_refcnt++;
+		ASSERT(gcdb->gcdb_refcnt != 0);
+
+		DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *,
+		    "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb);
+	} else if (alloc) {
+		gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP);
+		if (gcdb != NULL) {
+			gcdb->gcdb_refcnt = 1;
+			gcdb->gcdb_mask = rp->rtsa_mask;
+			gcdb->gcdb_doi = rp->rtsa_doi;
+			gcdb->gcdb_slrange = rp->rtsa_slrange;
+
+			if (mod_hash_insert(gcdb_hash,
+			    (mod_hash_key_t)&gcdb->gcdb_attr,
+			    (mod_hash_val_t)gcdb) != 0) {
+				mutex_exit(&gcdb_lock);
+				kmem_free(gcdb, sizeof (*gcdb));
+				return (NULL);
+			}
+
+			DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *,
+			    "gcdb(1) inserted in gcdb_hash(global)",
+			    tsol_gcdb_t *, gcdb);
+		}
+	}
+	mutex_exit(&gcdb_lock);
+	return (gcdb);
+}
+
+static void
+gcdb_inactive(tsol_gcdb_t *gcdb)
+{
+	ASSERT(MUTEX_HELD(&gcdb_lock));
+	ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0);
+
+	(void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr,
+	    (mod_hash_val_t *)&gcdb);
+
+	DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *,
+	    "gcdb(1) removed from gcdb_hash(global)",
+	    tsol_gcdb_t *, gcdb);
+	kmem_free(gcdb, sizeof (*gcdb));
+}
+
+tsol_gc_t *
+gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp)
+{
+	tsol_gc_t *gc;
+	tsol_gcdb_t *gcdb;
+
+	*gcgrp_xtrarefp = B_TRUE;
+
+	rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER);
+	if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) {
+		rw_exit(&gcgrp->gcgrp_rwlock);
+		return (NULL);
+	}
+
+	for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) {
+		if (gc->gc_db == gcdb) {
+			ASSERT(gc->gc_grp == gcgrp);
+
+			gc->gc_refcnt++;
+			ASSERT(gc->gc_refcnt != 0);
+
+			GCDB_REFRELE(gcdb);
+
+			DTRACE_PROBE3(tx__gcdb__log__info__gc__create,
+			    char *, "found gc(1) in gcgrp(2)",
+			    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
+			rw_exit(&gcgrp->gcgrp_rwlock);
+			return (gc);
+		}
+	}
+
+	gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP);
+	if (gc != NULL) {
+		if (gcgrp->gcgrp_head == NULL) {
+			gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc;
+		} else {
+			gcgrp->gcgrp_tail->gc_next = gc;
+			gc->gc_prev = gcgrp->gcgrp_tail;
+			gcgrp->gcgrp_tail = gc;
+		}
+		gcgrp->gcgrp_count++;
+		ASSERT(gcgrp->gcgrp_count != 0);
+
+		/* caller has incremented gcgrp reference for us */
+		gc->gc_grp = gcgrp;
+
+		gc->gc_db = gcdb;
+		gc->gc_refcnt = 1;
+
+		DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *,
+		    "added gc(1) to gcgrp(2)", tsol_gc_t *, gc,
+		    tsol_gcgrp_t *, gcgrp);
+
+		*gcgrp_xtrarefp = B_FALSE;
+	}
+	rw_exit(&gcgrp->gcgrp_rwlock);
+
+	return (gc);
+}
+
+void
+gc_inactive(tsol_gc_t *gc)
+{
+	tsol_gcgrp_t *gcgrp = gc->gc_grp;
+
+	ASSERT(gcgrp != NULL);
+	ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock));
+	ASSERT(gc->gc_refcnt == 0);
+
+	if (gc->gc_prev != NULL)
+		gc->gc_prev->gc_next = gc->gc_next;
+	else
+		gcgrp->gcgrp_head = gc->gc_next;
+	if (gc->gc_next != NULL)
+		gc->gc_next->gc_prev = gc->gc_prev;
+	else
+		gcgrp->gcgrp_tail = gc->gc_prev;
+	ASSERT(gcgrp->gcgrp_count > 0);
+	gcgrp->gcgrp_count--;
+
+	/* drop lock before it's destroyed */
+	rw_exit(&gcgrp->gcgrp_rwlock);
+
+	DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *,
+	    "removed inactive gc(1) from gcgrp(2)",
+	    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
+
+	GCGRP_REFRELE(gcgrp);
+
+	gc->gc_grp = NULL;
+	gc->gc_prev = gc->gc_next = NULL;
+
+	if (gc->gc_db != NULL)
+		GCDB_REFRELE(gc->gc_db);
+
+	kmem_free(gc, sizeof (*gc));
+}
+
+tsol_gcgrp_t *
+gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc)
+{
+	tsol_gcgrp_t *gcgrp = NULL;
+	mod_hash_t *hashp;
+
+	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
+
+	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
+
+	mutex_enter(&gcgrp_lock);
+	if (mod_hash_find(hashp, (mod_hash_key_t)ga,
+	    (mod_hash_val_t *)&gcgrp) == 0) {
+		gcgrp->gcgrp_refcnt++;
+		ASSERT(gcgrp->gcgrp_refcnt != 0);
+
+		DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *,
+		    "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp,
+		    mod_hash_t *, hashp);
+
+	} else if (alloc) {
+		gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP);
+		if (gcgrp != NULL) {
+			gcgrp->gcgrp_refcnt = 1;
+			rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL);
+			bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga));
+
+			if (mod_hash_insert(hashp,
+			    (mod_hash_key_t)&gcgrp->gcgrp_addr,
+			    (mod_hash_val_t)gcgrp) != 0) {
+				mutex_exit(&gcgrp_lock);
+				kmem_free(gcgrp, sizeof (*gcgrp));
+				return (NULL);
+			}
+
+			DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert,
+			    char *, "inserted gcgrp(1) in hash(2)",
+			    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
+		}
+	}
+	mutex_exit(&gcgrp_lock);
+	return (gcgrp);
+}
+
+void
+gcgrp_inactive(tsol_gcgrp_t *gcgrp)
+{
+	tsol_gcgrp_addr_t *ga;
+	mod_hash_t *hashp;
+
+	ASSERT(MUTEX_HELD(&gcgrp_lock));
+	ASSERT(!RW_LOCK_HELD(&gcgrp->gcgrp_rwlock));
+	ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0);
+	ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0);
+
+	ga = &gcgrp->gcgrp_addr;
+	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
+
+	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
+	(void) mod_hash_remove(hashp, (mod_hash_key_t)ga,
+	    (mod_hash_val_t *)&gcgrp);
+	rw_destroy(&gcgrp->gcgrp_rwlock);
+
+	DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *,
+	    "removed inactive gcgrp(1) from hash(2)",
+	    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
+
+	kmem_free(gcgrp, sizeof (*gcgrp));
+}
+
+/*
+ * Converts CIPSO option to sensitivity label.
+ * Validity checks based on restrictions defined in
+ * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity)
+ */
+static boolean_t
+cipso_to_sl(const uchar_t *option, bslabel_t *sl)
+{
+	const struct cipso_option *co = (const struct cipso_option *)option;
+	const struct cipso_tag_type_1 *tt1;
+
+	tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0];
+	if (tt1->tag_type != 1 ||
+	    tt1->tag_length < TSOL_TT1_MIN_LENGTH ||
+	    tt1->tag_length > TSOL_TT1_MAX_LENGTH ||
+	    tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length)
+		return (B_FALSE);
+
+	bsllow(sl);	/* assumed: sets compartments to all zeroes */
+	LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl);
+	bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments,
+	    tt1->tag_length - TSOL_TT1_MIN_LENGTH);
+	return (B_TRUE);
+}
+
+/*
+ * Parse the CIPSO label in the incoming packet and construct a ts_label_t
+ * that reflects the CIPSO label and attach it to the dblk cred. Later as
+ * the mblk flows up through the stack any code that needs to examine the
+ * packet label can inspect the label from the dblk cred. This function is
+ * called right in ip_rput for all packets, i.e. locally destined and
+ * to be forwarded packets. The forwarding path needs to examine the label
+ * to determine how to forward the packet.
+ *
+ * For IPv4, IP header options have been pulled up, but other headers might not
+ * have been.  For IPv6, any hop-by-hop options have been pulled up, but any
+ * other headers might not be present.
+ */
+boolean_t
+tsol_get_pkt_label(mblk_t *mp, int version)
+{
+	tsol_tpc_t	*src_rhtp;
+	uchar_t		*opt_ptr = NULL;
+	const ipha_t	*ipha;
+	bslabel_t	sl;
+	uint32_t	doi;
+	tsol_ip_label_t	label_type;
+	const cipso_option_t *co;
+	const void	*src;
+	const ip6_t	*ip6h;
+
+	ASSERT(DB_TYPE(mp) == M_DATA);
+
+	if (version == IPV4_VERSION) {
+		ipha = (const ipha_t *)mp->b_rptr;
+		src = &ipha->ipha_src;
+		label_type = tsol_get_option(mp, &opt_ptr);
+	} else {
+		uchar_t		*after_secopt;
+		boolean_t	hbh_needed;
+		const uchar_t	*ip6hbh;
+		size_t		optlen;
+
+		label_type = OPT_NONE;
+		ip6h = (const ip6_t *)mp->b_rptr;
+		src = &ip6h->ip6_src;
+		if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
+			ip6hbh = (const uchar_t *)&ip6h[1];
+			optlen = (ip6hbh[1] + 1) << 3;
+			ASSERT(ip6hbh + optlen <= mp->b_wptr);
+			opt_ptr = tsol_find_secopt_v6(ip6hbh, optlen,
+			    &after_secopt, &hbh_needed);
+			/* tsol_find_secopt_v6 guarantees some sanity */
+			if (opt_ptr != NULL &&
+			    (optlen = opt_ptr[1]) >= 8) {
+				opt_ptr += 2;
+				bcopy(opt_ptr, &doi, sizeof (doi));
+				doi = ntohl(doi);
+				if (doi == IP6LS_DOI_V4 &&
+				    opt_ptr[4] == IP6LS_TT_V4 &&
+				    opt_ptr[5] <= optlen - 4 &&
+				    opt_ptr[7] <= optlen - 6) {
+					opt_ptr += sizeof (doi) + 2;
+					label_type = OPT_CIPSO;
+				}
+			}
+		}
+	}
+
+	switch (label_type) {
+	case OPT_CIPSO:
+		/*
+		 * Convert the CIPSO label to the internal format
+		 * and attach it to the dblk cred.
+		 * Validity checks based on restrictions defined in
+		 * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
+		 * (draft-ietf-cipso-ipsecurity)
+		 */
+		if (version == IPV6_VERSION && ip6opt_ls == 0)
+			return (B_FALSE);
+		co = (const struct cipso_option *)opt_ptr;
+		if ((co->cipso_length <
+		    TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) ||
+		    (co->cipso_length > IP_MAX_OPT_LENGTH))
+			return (B_FALSE);
+		bcopy(co->cipso_doi, &doi, sizeof (doi));
+		doi = ntohl(doi);
+		if (!cipso_to_sl(opt_ptr, &sl))
+			return (B_FALSE);
+		setbltype(&sl, SUN_SL_ID);
+		break;
+
+	case OPT_NONE:
+		/*
+		 * Handle special cases that are not currently labeled, even
+		 * though the sending system may otherwise be configured as
+		 * labeled.
+		 *	- IGMP
+		 *	- IPv4 ICMP Router Discovery
+		 *	- IPv6 Neighbor Discovery
+		 */
+		if (version == IPV4_VERSION) {
+			if (ipha->ipha_protocol == IPPROTO_IGMP)
+				return (B_TRUE);
+			if (ipha->ipha_protocol == IPPROTO_ICMP) {
+				const struct icmp *icmp = (const struct icmp *)
+				    (mp->b_rptr + IPH_HDR_LENGTH(ipha));
+
+				if ((uchar_t *)icmp > mp->b_wptr) {
+					if (!pullupmsg(mp,
+					    (uchar_t *)icmp - mp->b_rptr + 1))
+						return (B_FALSE);
+					icmp = (const struct icmp *)
+					    (mp->b_rptr +
+					    IPH_HDR_LENGTH(ipha));
+				}
+				if (icmp->icmp_type == ICMP_ROUTERADVERT ||
+				    icmp->icmp_type == ICMP_ROUTERSOLICIT)
+					return (B_TRUE);
+			}
+			src = &ipha->ipha_src;
+		} else {
+			if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
+				const icmp6_t *icmp6 = (const icmp6_t *)
+				    (mp->b_rptr + IPV6_HDR_LEN);
+
+				if ((uchar_t *)icmp6 + ICMP6_MINLEN >
+				    mp->b_wptr) {
+					if (!pullupmsg(mp,
+					    (uchar_t *)icmp6 - mp->b_rptr +
+					    ICMP6_MINLEN))
+						return (B_FALSE);
+					icmp6 = (const icmp6_t *)
+					    (mp->b_rptr + IPV6_HDR_LEN);
+				}
+				if (icmp6->icmp6_type >= MLD_LISTENER_QUERY &&
+				    icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE)
+					return (B_TRUE);
+			}
+			src = &ip6h->ip6_src;
+		}
+
+		/*
+		 * Look up the tnrhtp database and get the implicit label
+		 * that is associated with this unlabeled host and attach
+		 * it to the packet.
+		 */
+		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
+			return (B_FALSE);
+
+		/* If the sender is labeled, drop the unlabeled packet. */
+		if (src_rhtp->tpc_tp.host_type != UNLABELED) {
+			TPC_RELE(src_rhtp);
+			pr_addr_dbg("unlabeled packet forged from %s\n",
+			    version == IPV4_VERSION ? AF_INET : AF_INET6, src);
+			return (B_FALSE);
+		}
+
+		sl = src_rhtp->tpc_tp.tp_def_label;
+		setbltype(&sl, SUN_SL_ID);
+		doi = src_rhtp->tpc_tp.tp_doi;
+		TPC_RELE(src_rhtp);
+		break;
+
+	default:
+		return (B_FALSE);
+	}
+
+	/* Make sure no other thread is messing with this mblk */
+	ASSERT(DB_REF(mp) == 1);
+	if (DB_CRED(mp) == NULL) {
+		DB_CRED(mp) = newcred_from_bslabel(&sl, doi, KM_NOSLEEP);
+		if (DB_CRED(mp) == NULL)
+			return (B_FALSE);
+	} else {
+		cred_t	*newcr;
+
+		newcr = copycred_from_bslabel(DB_CRED(mp), &sl, doi,
+		    KM_NOSLEEP);
+		if (newcr == NULL)
+			return (B_FALSE);
+		crfree(DB_CRED(mp));
+		DB_CRED(mp) = newcr;
+	}
+
+	/*
+	 * If the source was unlabeled, then flag as such,
+	 * while remembering that CIPSO routers add headers.
+	 */
+	if (label_type == OPT_NONE)
+		crgetlabel(DB_CRED(mp))->tsl_flags |= TSLF_UNLABELED;
+	else if (label_type == OPT_CIPSO) {
+		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
+			return (B_FALSE);
+		if (src_rhtp->tpc_tp.host_type == UNLABELED)
+		    crgetlabel(DB_CRED(mp))->tsl_flags |=
+		    TSLF_UNLABELED;
+		TPC_RELE(src_rhtp);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * This routine determines whether the given packet should be accepted locally.
+ * It does a range/set check on the packet's label by looking up the given
+ * address in the remote host database.
+ */
+boolean_t
+tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
+    boolean_t shared_addr, const conn_t *connp)
+{
+	const cred_t *credp;
+	ts_label_t *plabel, *conn_plabel;
+	tsol_tpc_t *tp;
+	boolean_t retv;
+	const bslabel_t *label, *conn_label;
+
+	/*
+	 * The cases in which this can happen are:
+	 *	- IPv6 Router Alert, where ip_rput_data_v6 deliberately skips
+	 *	  over the label attachment process.
+	 *	- MLD output looped-back to ourselves.
+	 *	- IPv4 Router Discovery, where tsol_get_pkt_label intentionally
+	 *	  avoids the labeling process.
+	 * We trust that all valid paths in the code set the cred pointer when
+	 * needed.
+	 */
+	if ((credp = DB_CRED(mp)) == NULL)
+		return (B_TRUE);
+
+	/*
+	 * If this packet is from the inside (not a remote host) and has the
+	 * same zoneid as the selected destination, then no checks are
+	 * necessary.  Membership in the zone is enough proof.  This is
+	 * intended to be a hot path through this function.
+	 */
+	if (!crisremote(credp) &&
+	    crgetzone(credp) == crgetzone(connp->conn_cred))
+		return (B_TRUE);
+
+	plabel = crgetlabel(credp);
+	conn_plabel = crgetlabel(connp->conn_cred);
+	ASSERT(plabel != NULL && conn_plabel != NULL);
+
+	label = label2bslabel(plabel);
+	conn_label = label2bslabel(crgetlabel(connp->conn_cred));
+
+	/*
+	 * MLPs are always validated using the range and set of the local
+	 * address, even when the remote host is unlabeled.
+	 */
+	if (connp->conn_mlp_type == mlptBoth ||
+	/* LINTED: no consequent */
+	    connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) {
+		;
+
+	/*
+	 * If this is a packet from an unlabeled sender, then we must apply
+	 * different rules.  If the label is equal to the zone's label, then
+	 * it's allowed.  If it's not equal, but the zone is either the global
+	 * zone or the label is dominated by the zone's label, then allow it
+	 * as long as it's in the range configured for the destination.
+	 */
+	} else if (plabel->tsl_flags & TSLF_UNLABELED) {
+		if (plabel->tsl_doi == conn_plabel->tsl_doi &&
+		    blequal(label, conn_label))
+			return (B_TRUE);
+
+		if (!connp->conn_mac_exempt ||
+		    (connp->conn_zoneid != GLOBAL_ZONEID &&
+		    (plabel->tsl_doi != conn_plabel->tsl_doi ||
+		    !bldominates(conn_label, label)))) {
+			DTRACE_PROBE3(
+			    tx__ip__log__drop__receivelocal__mac_unl,
+			    char *,
+			    "unlabeled packet mp(1) fails mac for conn(2)",
+			    mblk_t *, mp, conn_t *, connp);
+			return (B_FALSE);
+		}
+
+	/*
+	 * If this is a private address and the connection is SLP for private
+	 * addresses, then the only thing that matters is the label on the
+	 * zone, which is the same as the label on the connection.  We don't
+	 * care (and don't have to care) about the tnrhdb.
+	 */
+	} else if (!shared_addr) {
+		/*
+		 * Since this is a zone-specific address, we know that any MLP
+		 * case should have been handled up above.  That means this
+		 * connection must not be MLP for zone-specific addresses.  We
+		 * assert that to be true.
+		 */
+		ASSERT(connp->conn_mlp_type == mlptSingle ||
+		    connp->conn_mlp_type == mlptShared);
+		if (plabel->tsl_doi == conn_plabel->tsl_doi &&
+		    blequal(label, conn_label))
+			return (B_TRUE);
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp,
+		    char *, "packet mp(1) fails exactly SLP match conn(2)",
+		    mblk_t *, mp, conn_t *, connp);
+		return (B_FALSE);
+	}
+
+	tp = find_tpc(addr, version, B_FALSE);
+	if (tp == NULL) {
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr,
+		    char *, "dropping mp(1), host(2) lacks entry",
+		    mblk_t *, mp, void *, addr);
+		return (B_FALSE);
+	}
+
+	/*
+	 * The local host address should not be unlabeled at this point.  The
+	 * only way this can happen is that the destination isn't unicast.  We
+	 * assume that the packet should not have had a label, and thus should
+	 * have been handled by the TSLF_UNLABELED logic above.
+	 */
+	if (tp->tpc_tp.host_type == UNLABELED) {
+		retv = B_FALSE;
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *,
+		    "mp(1) unlabeled source, but tp is not unlabeled.",
+		    mblk_t *, mp, tsol_tpc_t *, tp);
+
+	} else if (tp->tpc_tp.host_type != SUN_CIPSO) {
+		retv = B_FALSE;
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *,
+		    "delivering mp(1), found unrecognized tpc(2) type.",
+		    mblk_t *, mp, tsol_tpc_t *, tp);
+
+	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
+		retv = B_FALSE;
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
+		    "mp(1) could not be delievered to tp(2), doi mismatch",
+		    mblk_t *, mp, tsol_tpc_t *, tp);
+
+	} else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) &&
+	    !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) {
+		retv = B_FALSE;
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
+		    "mp(1) could not be delievered to tp(2), bad mac",
+		    mblk_t *, mp, tsol_tpc_t *, tp);
+	} else {
+		retv = B_TRUE;
+	}
+
+	TPC_RELE(tp);
+
+	return (retv);
+}
+
+boolean_t
+tsol_can_accept_raw(mblk_t *mp, boolean_t check_host)
+{
+	ts_label_t	*plabel = NULL;
+	tsol_tpc_t	*src_rhtp, *dst_rhtp;
+	boolean_t	retv;
+
+	if (DB_CRED(mp) != NULL)
+		plabel = crgetlabel(DB_CRED(mp));
+
+	/* We are bootstrapping or the internal template was never deleted */
+	if (plabel == NULL)
+		return (B_TRUE);
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		ipha_t *ipha = (ipha_t *)mp->b_rptr;
+
+		src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION,
+		    B_FALSE);
+		if (src_rhtp == NULL)
+			return (B_FALSE);
+		dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION,
+		    B_FALSE);
+	} else {
+		ip6_t *ip6h = (ip6_t *)mp->b_rptr;
+
+		src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION,
+		    B_FALSE);
+		if (src_rhtp == NULL)
+			return (B_FALSE);
+		dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION,
+		    B_FALSE);
+	}
+	if (dst_rhtp == NULL) {
+		TPC_RELE(src_rhtp);
+		return (B_FALSE);
+	}
+
+	if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) {
+		retv = B_FALSE;
+
+	/*
+	 * Check that the packet's label is in the correct range for labeled
+	 * sender, or is equal to the default label for unlabeled sender.
+	 */
+	} else if ((src_rhtp->tpc_tp.host_type != UNLABELED &&
+	    !_blinrange(label2bslabel(plabel),
+	    &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
+	    !blinlset(label2bslabel(plabel),
+	    src_rhtp->tpc_tp.tp_sl_set_cipso)) ||
+	    (src_rhtp->tpc_tp.host_type == UNLABELED &&
+	    !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) {
+		retv = B_FALSE;
+
+	} else if (check_host) {
+		retv = B_TRUE;
+
+	/*
+	 * Until we have SL range in the Zone structure, pass it
+	 * when our own address lookup returned an internal entry.
+	 */
+	} else switch (dst_rhtp->tpc_tp.host_type) {
+	case UNLABELED:
+		retv = B_TRUE;
+		break;
+
+	case SUN_CIPSO:
+		retv = _blinrange(label2bslabel(plabel),
+		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) ||
+		    blinlset(label2bslabel(plabel),
+		    dst_rhtp->tpc_tp.tp_sl_set_cipso);
+		break;
+
+	default:
+		retv = B_FALSE;
+	}
+	TPC_RELE(src_rhtp);
+	TPC_RELE(dst_rhtp);
+	return (retv);
+}
+
+/*
+ * This routine determines whether a response to a failed packet delivery or
+ * connection should be sent back.  By default, the policy is to allow such
+ * messages to be sent at all times, as these messages reveal little useful
+ * information and are healthy parts of TCP/IP networking.
+ *
+ * If tsol_strict_error is set, then we do strict tests: if the packet label is
+ * within the label range/set of this host/zone, return B_TRUE; otherwise
+ * return B_FALSE, which causes the packet to be dropped silently.
+ *
+ * Note that tsol_get_pkt_label will cause the packet to drop if the sender is
+ * marked as labeled in the remote host database, but the packet lacks a label.
+ * This means that we don't need to do a lookup on the source; the
+ * TSLF_UNLABELED flag is sufficient.
+ */
+boolean_t
+tsol_can_reply_error(const mblk_t *mp)
+{
+	ts_label_t	*plabel = NULL;
+	tsol_tpc_t	*rhtp;
+	const ipha_t	*ipha;
+	const ip6_t	*ip6h;
+	boolean_t	retv;
+	bslabel_t	*pktbs;
+
+	/* Caller must pull up at least the IP header */
+	ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ?
+	    sizeof (*ipha) : sizeof (*ip6h)));
+
+	if (!tsol_strict_error)
+		return (B_TRUE);
+
+	if (DB_CRED(mp) != NULL)
+		plabel = crgetlabel(DB_CRED(mp));
+
+	/* We are bootstrapping or the internal template was never deleted */
+	if (plabel == NULL)
+		return (B_TRUE);
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		ipha = (const ipha_t *)mp->b_rptr;
+		rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
+	} else {
+		ip6h = (const ip6_t *)mp->b_rptr;
+		rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE);
+	}
+
+	if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) {
+		retv = B_FALSE;
+	} else {
+		/*
+		 * If we're in the midst of forwarding, then the destination
+		 * address might not be labeled.  In that case, allow unlabeled
+		 * packets through only if the default label is the same, and
+		 * labeled ones if they dominate.
+		 */
+		pktbs = label2bslabel(plabel);
+		switch (rhtp->tpc_tp.host_type) {
+		case UNLABELED:
+			if (plabel->tsl_flags & TSLF_UNLABELED) {
+				retv = blequal(pktbs,
+				    &rhtp->tpc_tp.tp_def_label);
+			} else {
+				retv = bldominates(pktbs,
+				    &rhtp->tpc_tp.tp_def_label);
+			}
+			break;
+
+		case SUN_CIPSO:
+			retv = _blinrange(pktbs,
+			    &rhtp->tpc_tp.tp_sl_range_cipso) ||
+			    blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso);
+			break;
+
+		default:
+			retv = B_FALSE;
+			break;
+		}
+	}
+
+	if (rhtp != NULL)
+		TPC_RELE(rhtp);
+
+	return (retv);
+}
+
+/*
+ * Finds the zone associated with the given packet.  Returns GLOBAL_ZONEID if
+ * the zone cannot be located.
+ *
+ * This is used by the classifier when the packet matches an ALL_ZONES IRE, and
+ * there's no MLP defined.
+ */
+zoneid_t
+tsol_packet_to_zoneid(const mblk_t *mp)
+{
+	cred_t *cr = DB_CRED(mp);
+	zone_t *zone;
+	ts_label_t *label;
+
+	if (cr != NULL) {
+		if ((label = crgetlabel(cr)) != NULL) {
+			zone = zone_find_by_label(label);
+			if (zone != NULL) {
+				zoneid_t zoneid = zone->zone_id;
+
+				zone_rele(zone);
+				return (zoneid);
+			}
+		}
+	}
+	return (GLOBAL_ZONEID);
+}
+
+int
+tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl)
+{
+	int		error = 0;
+	tsol_ire_gw_secattr_t *attrp = NULL;
+	tsol_tnrhc_t	*gw_rhc = NULL;
+	tsol_gcgrp_t	*gcgrp = NULL;
+	tsol_gc_t	*gc = NULL;
+	in_addr_t	ga_addr4;
+	void		*paddr = NULL;
+
+	/* Not in Trusted mode or IRE is local/loopback/broadcast/interface */
+	if (!is_system_labeled() ||
+	    (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST |
+	    IRE_INTERFACE)))
+		goto done;
+
+	/*
+	 * If we don't have a label to compare with, or the IRE does not
+	 * contain any gateway security attributes, there's not much that
+	 * we can do.  We let the former case pass, and the latter fail,
+	 * since the IRE doesn't qualify for a match due to the lack of
+	 * security attributes.
+	 */
+	if (tsl == NULL || ire->ire_gw_secattr == NULL) {
+		if (tsl != NULL) {
+			DTRACE_PROBE3(
+			tx__ip__log__drop__irematch__nogwsec, char *,
+			"ire(1) lacks ire_gw_secattr when matching label(2)",
+			ire_t *, ire, ts_label_t *, tsl);
+			error = EACCES;
+		}
+		goto done;
+	}
+
+	attrp = ire->ire_gw_secattr;
+
+	/*
+	 * The possible lock order scenarios related to the tsol gateway
+	 * attribute locks are documented at the beginning of ip.c in the
+	 * lock order scenario section.
+	 */
+	mutex_enter(&attrp->igsa_lock);
+
+	/*
+	 * Depending on the IRE type (prefix vs. cache), we seek the group
+	 * structure which contains all security credentials of the gateway.
+	 * A prefix IRE is associated with at most one gateway credential,
+	 * while a cache IRE is associated with every credentials that the
+	 * gateway has.
+	 */
+	if ((gc = attrp->igsa_gc) != NULL) {			/* prefix */
+		gcgrp = gc->gc_grp;
+		ASSERT(gcgrp != NULL);
+		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+	} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {	/* cache */
+		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
+		gc = gcgrp->gcgrp_head;
+		if (gc == NULL) {
+			/* gc group is empty, so the drop lock now */
+			ASSERT(gcgrp->gcgrp_count == 0);
+			rw_exit(&gcgrp->gcgrp_rwlock);
+			gcgrp = NULL;
+		}
+	}
+
+	if (gcgrp != NULL)
+		GCGRP_REFHOLD(gcgrp);
+
+	if ((gw_rhc = attrp->igsa_rhc) != NULL) {
+		/*
+		 * If our cached entry has grown stale, then discard it so we
+		 * can get a new one.
+		 */
+		if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) {
+			TNRHC_RELE(gw_rhc);
+			attrp->igsa_rhc = gw_rhc = NULL;
+		} else {
+			TNRHC_HOLD(gw_rhc)
+		}
+	}
+
+	/* Last attempt at loading the template had failed; try again */
+	if (gw_rhc == NULL) {
+		if (gcgrp != NULL) {
+			tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
+
+			if (ire->ire_ipversion == IPV4_VERSION) {
+				ASSERT(ga->ga_af == AF_INET);
+				IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
+				paddr = &ga_addr4;
+			} else {
+				ASSERT(ga->ga_af == AF_INET6);
+				paddr = &ga->ga_addr;
+			}
+		} else if (ire->ire_ipversion == IPV6_VERSION &&
+		    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
+			paddr = &ire->ire_gateway_addr_v6;
+		} else if (ire->ire_ipversion == IPV4_VERSION &&
+		    ire->ire_gateway_addr != INADDR_ANY) {
+			paddr = &ire->ire_gateway_addr;
+		}
+
+		/* We've found a gateway address to do the template lookup */
+		if (paddr != NULL) {
+			ASSERT(gw_rhc == NULL);
+			if (ire->ire_ipversion == IPV4_VERSION)
+				gw_rhc = find_rhc_v4(paddr);
+			else
+				gw_rhc = find_rhc_v6(paddr);
+			if (gw_rhc != NULL) {
+				/*
+				 * Note that if the lookup above returned an
+				 * internal template, we'll use it for the
+				 * time being, and do another lookup next
+				 * time around.
+				 */
+				/* Another thread has loaded the template? */
+				if (attrp->igsa_rhc != NULL) {
+					TNRHC_RELE(gw_rhc)
+					/* reload, it could be different */
+					gw_rhc = attrp->igsa_rhc;
+				} else {
+					attrp->igsa_rhc = gw_rhc;
+				}
+				/*
+				 * Hold an extra reference just like we did
+				 * above prior to dropping the igsa_lock.
+				 */
+				TNRHC_HOLD(gw_rhc)
+			}
+		}
+	}
+
+	mutex_exit(&attrp->igsa_lock);
+	/* Gateway template not found */
+	if (gw_rhc == NULL) {
+		/*
+		 * If destination address is directly reachable through an
+		 * interface rather than through a learned route, pass it.
+		 */
+		if (paddr != NULL) {
+			DTRACE_PROBE3(
+			    tx__ip__log__drop__irematch__nogwtmpl, char *,
+			    "ire(1), label(2) off-link with no gw_rhc",
+			    ire_t *, ire, ts_label_t *, tsl);
+			error = EINVAL;
+		}
+		goto done;
+	}
+
+	if (gc != NULL) {
+		tsol_gcdb_t *gcdb;
+		/*
+		 * In the case of IRE_CACHE we've got one or more gateway
+		 * security credentials to compare against the passed in label.
+		 * Perform label range comparison against each security
+		 * credential of the gateway. In the case of a prefix ire
+		 * we need to match against the security attributes of
+		 * just the route itself, so the loop is executed only once.
+		 */
+		ASSERT(gcgrp != NULL);
+		do {
+			gcdb = gc->gc_db;
+			if (tsl->tsl_doi == gcdb->gcdb_doi &&
+			    _blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange))
+				break;
+			if (ire->ire_type == IRE_CACHE)
+				gc = gc->gc_next;
+			else
+				gc = NULL;
+		} while (gc != NULL);
+
+		if (gc == NULL) {
+			DTRACE_PROBE3(
+			    tx__ip__log__drop__irematch__nogcmatched,
+			    char *, "ire(1), tsl(2): all gc failed match",
+			    ire_t *, ire, ts_label_t *, tsl);
+			error = EACCES;
+		}
+	} else {
+		/*
+		 * We didn't find any gateway credentials in the IRE
+		 * attributes; fall back to the gateway's template for
+		 * label range checks, if we are required to do so.
+		 */
+		ASSERT(gw_rhc != NULL);
+		switch (gw_rhc->rhc_tpc->tpc_tp.host_type) {
+		case SUN_CIPSO:
+			if (tsl->tsl_doi !=
+			    gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
+			    (!_blinrange(&tsl->tsl_label,
+			    &gw_rhc->rhc_tpc->tpc_tp.
+			    tp_sl_range_cipso) &&
+			    !blinlset(&tsl->tsl_label,
+			    gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) {
+				error = EACCES;
+				DTRACE_PROBE4(
+				    tx__ip__log__drop__irematch__deftmpl,
+				    char *, "ire(1), tsl(2), gw_rhc(3) "
+				    "failed match (cipso gw)",
+				    ire_t *, ire, ts_label_t *, tsl,
+				    tsol_tnrhc_t *, gw_rhc);
+			}
+			break;
+
+		case UNLABELED:
+			if (tsl->tsl_doi !=
+				gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
+			    (!_blinrange(&tsl->tsl_label,
+			    &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) &&
+			    !blinlset(&tsl->tsl_label,
+			    gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) {
+				error = EACCES;
+				DTRACE_PROBE4(
+				    tx__ip__log__drop__irematch__deftmpl,
+				    char *, "ire(1), tsl(2), gw_rhc(3) "
+				    "failed match (unlabeled gw)",
+				    ire_t *, ire, ts_label_t *, tsl,
+				    tsol_tnrhc_t *, gw_rhc);
+			}
+			break;
+		}
+	}
+
+done:
+
+	if (gcgrp != NULL) {
+		rw_exit(&gcgrp->gcgrp_rwlock);
+		GCGRP_REFRELE(gcgrp);
+	}
+
+	if (gw_rhc != NULL)
+		TNRHC_RELE(gw_rhc)
+
+	return (error);
+}
+
+/*
+ * Performs label accreditation checks for packet forwarding.
+ *
+ * Returns a pointer to the modified mblk if allowed for forwarding,
+ * or NULL if the packet must be dropped.
+ */
+mblk_t *
+tsol_ip_forward(ire_t *ire, mblk_t *mp)
+{
+	tsol_ire_gw_secattr_t *attrp = NULL;
+	ipha_t		*ipha;
+	ip6_t		*ip6h;
+	const void	*pdst;
+	const void	*psrc;
+	boolean_t	off_link;
+	tsol_tpc_t	*dst_rhtp, *gw_rhtp;
+	tsol_ip_label_t label_type;
+	uchar_t		*opt_ptr = NULL;
+	ts_label_t	*tsl;
+	uint8_t		proto;
+	int		af, adjust;
+	uint16_t	iplen;
+
+	ASSERT(ire != NULL && mp != NULL);
+	ASSERT(ire->ire_stq != NULL);
+
+	af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6;
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		ASSERT(ire->ire_ipversion == IPV4_VERSION);
+		ipha = (ipha_t *)mp->b_rptr;
+		psrc = &ipha->ipha_src;
+		pdst = &ipha->ipha_dst;
+		proto = ipha->ipha_protocol;
+
+		/* destination not directly reachable? */
+		off_link = (ire->ire_gateway_addr != INADDR_ANY);
+	} else {
+		ASSERT(ire->ire_ipversion == IPV6_VERSION);
+		ip6h = (ip6_t *)mp->b_rptr;
+		psrc = &ip6h->ip6_src;
+		pdst = &ip6h->ip6_dst;
+		proto = ip6h->ip6_nxt;
+
+		if (proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
+		    proto != IPPROTO_ICMPV6) {
+			uint8_t *nexthdrp;
+			uint16_t hdr_len;
+
+			if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len,
+			    &nexthdrp)) {
+				/* malformed packet; drop it */
+				return (NULL);
+			}
+			proto = *nexthdrp;
+		}
+
+		/* destination not directly reachable? */
+		off_link = !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6);
+	}
+
+	if ((tsl = MBLK_GETLABEL(mp)) == NULL)
+		return (mp);
+
+	label_type = tsol_get_option(mp, &opt_ptr);
+
+	ASSERT(psrc != NULL && pdst != NULL);
+	dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
+
+	if (dst_rhtp == NULL) {
+		/*
+		 * Without a template we do not know if forwarding
+		 * violates MAC
+		 */
+		DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *,
+		    "mp(1) dropped, no template for destination ip4|6(2)",
+		    mblk_t *, mp, void *, pdst);
+		return (NULL);
+	}
+
+	/*
+	 * Gateway template must have existed for off-link destinations,
+	 * since tsol_ire_match_gwattr has ensured such condition.
+	 */
+	if (((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL ||
+	    (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) {
+		DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
+		    "mp(1) dropped, no gateway in ire attributes(2)",
+		    mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
+		mp = NULL;
+		goto keep_label;
+	}
+
+	/*
+	 * Check that the label for the packet is acceptable
+	 * by destination host; otherwise, drop it.
+	 */
+	switch (dst_rhtp->tpc_tp.host_type) {
+	case SUN_CIPSO:
+		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
+		    (!_blinrange(&tsl->tsl_label,
+		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
+		    !blinlset(&tsl->tsl_label,
+		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
+			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
+			    "labeled packet mp(1) dropped, label(2) fails "
+			    "destination(3) accredation check",
+			    mblk_t *, mp, ts_label_t *, tsl,
+			    tsol_tpc_t *, dst_rhtp);
+			mp = NULL;
+			goto keep_label;
+		}
+		break;
+
+
+	case UNLABELED:
+		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
+		    !blequal(&dst_rhtp->tpc_tp.tp_def_label,
+		    &tsl->tsl_label)) {
+			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
+			    "unlabeled packet mp(1) dropped, label(2) fails "
+			    "destination(3) accredation check",
+			    mblk_t *, mp, ts_label_t *, tsl,
+			    tsol_tpc_t *, dst_rhtp);
+			mp = NULL;
+			goto keep_label;
+		}
+		break;
+	}
+	if (label_type == OPT_CIPSO) {
+		/*
+		 * We keep the label on any of the following cases:
+		 *
+		 *   1. The destination is labeled (on/off-link).
+		 *   2. The unlabeled destination is off-link,
+		 *	and the next hop gateway is labeled.
+		 */
+		if (dst_rhtp->tpc_tp.host_type != UNLABELED ||
+		    (off_link &&
+		    gw_rhtp->tpc_tp.host_type != UNLABELED))
+			goto keep_label;
+
+		/*
+		 * Strip off the CIPSO option from the packet because: the
+		 * unlabeled destination host is directly reachable through
+		 * an interface (on-link); or, the unlabeled destination host
+		 * is not directly reachable (off-link), and the next hop
+		 * gateway is unlabeled.
+		 */
+		adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) :
+		    tsol_remove_secopt_v6(ip6h, MBLKL(mp));
+
+		ASSERT(adjust <= 0);
+		if (adjust != 0) {
+
+			/* adjust is negative */
+			ASSERT((mp->b_wptr + adjust) >= mp->b_rptr);
+			mp->b_wptr += adjust;
+
+			if (af == AF_INET) {
+				ipha = (ipha_t *)mp->b_rptr;
+				iplen = ntohs(ipha->ipha_length) + adjust;
+				ipha->ipha_length = htons(iplen);
+				ipha->ipha_hdr_checksum = 0;
+				ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
+			}
+			DTRACE_PROBE3(tx__ip__log__info__forward__adjust,
+			    char *,
+			    "mp(1) adjusted(2) for CIPSO option removal",
+			    mblk_t *, mp, int, adjust);
+		}
+		goto keep_label;
+	}
+
+	ASSERT(label_type == OPT_NONE);
+	ASSERT(dst_rhtp != NULL);
+
+	/*
+	 * We need to add CIPSO option if the destination or the next hop
+	 * gateway is labeled.  Otherwise, pass the packet as is.
+	 */
+	if (dst_rhtp->tpc_tp.host_type == UNLABELED &&
+	    (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED))
+		goto keep_label;
+
+	if ((af == AF_INET &&
+	    tsol_check_label(DB_CRED(mp), &mp, &adjust, B_FALSE) != 0) ||
+	    (af == AF_INET6 &&
+	    tsol_check_label_v6(DB_CRED(mp), &mp, &adjust, B_FALSE) != 0)) {
+		mp = NULL;
+		goto keep_label;
+	}
+
+	ASSERT(adjust != -1);
+	if (adjust != 0) {
+		if (af == AF_INET) {
+			ipha = (ipha_t *)mp->b_rptr;
+			iplen = ntohs(ipha->ipha_length) + adjust;
+			ipha->ipha_length = htons(iplen);
+			ipha->ipha_hdr_checksum = 0;
+			ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
+		}
+
+		DTRACE_PROBE3(tx__ip__log__info__forward__adjust, char *,
+		    "mp(1) adjusted(2) for CIPSO option removal",
+		    mblk_t *, mp, int, adjust);
+	}
+
+keep_label:
+	TPC_RELE(dst_rhtp);
+	return (mp);
+}
+
+/*
+ * Name:	tsol_rtsa_init()
+ *
+ * Normal:	Sanity checks on the route security attributes provided by
+ *		user.  Convert it into a route security parameter list to
+ *		be returned to caller.
+ *
+ * Output:	EINVAL if bad security attributes in the routing message
+ *		ENOMEM if unable to allocate data structures
+ *		0 otherwise.
+ *
+ * Note:	On input, cp must point to the end of any addresses in
+ *		the rt_msghdr_t structure.
+ */
+int
+tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp)
+{
+	uint_t	sacnt;
+	int	err;
+	caddr_t	lim;
+	tsol_rtsecattr_t *tp;
+
+	ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL);
+
+	/*
+	 * In theory, we could accept as many security attributes configured
+	 * per route destination.  However, the current design is limited
+	 * such that at most only one set security attributes is allowed to
+	 * be associated with a prefix IRE.  We therefore assert for now.
+	 */
+	/* LINTED */
+	ASSERT(TSOL_RTSA_REQUEST_MAX == 1);
+
+	sp->rtsa_cnt = 0;
+	lim = (caddr_t)rtm + rtm->rtm_msglen;
+	ASSERT(cp <= lim);
+
+	if ((lim - cp) < sizeof (rtm_ext_t) ||
+	    ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR)
+		return (0);
+
+	if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t))
+		return (EINVAL);
+
+	cp += sizeof (rtm_ext_t);
+
+	if ((lim - cp) < sizeof (*tp) ||
+	    (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) ||
+	    (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt))
+		return (EINVAL);
+
+	/*
+	 * Trying to add route security attributes when system
+	 * labeling service is not available, or when user supllies
+	 * more than the maximum number of security attributes
+	 * allowed per request.
+	 */
+	if ((sacnt > 0 && !is_system_labeled()) ||
+	    sacnt > TSOL_RTSA_REQUEST_MAX)
+		return (EINVAL);
+
+	/* Ensure valid credentials */
+	if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)->
+	    rtsa_attr[0])) != 0) {
+		cp += sizeof (*sp);
+		return (err);
+	}
+
+	bcopy(cp, sp, sizeof (*sp));
+	cp += sizeof (*sp);
+	return (0);
+}
+
+int
+tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc,
+    tsol_gcgrp_t *gcgrp)
+{
+	tsol_ire_gw_secattr_t *attrp;
+	boolean_t exists = B_FALSE;
+	in_addr_t ga_addr4;
+	void *paddr = NULL;
+
+	ASSERT(ire != NULL);
+
+	/*
+	 * The only time that attrp can be NULL is when this routine is
+	 * called for the first time during the creation/initialization
+	 * of the corresponding IRE.  It will only get cleared when the
+	 * IRE is deleted.
+	 */
+	if ((attrp = ire->ire_gw_secattr) == NULL) {
+		attrp = ire_gw_secattr_alloc(KM_NOSLEEP);
+		if (attrp == NULL)
+			return (ENOMEM);
+		ire->ire_gw_secattr = attrp;
+	} else {
+		exists = B_TRUE;
+		mutex_enter(&attrp->igsa_lock);
+
+		if (attrp->igsa_rhc != NULL) {
+			TNRHC_RELE(attrp->igsa_rhc);
+			attrp->igsa_rhc = NULL;
+		}
+
+		if (attrp->igsa_gc != NULL)
+			GC_REFRELE(attrp->igsa_gc);
+		if (attrp->igsa_gcgrp != NULL)
+			GCGRP_REFRELE(attrp->igsa_gcgrp);
+	}
+	ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock));
+
+	/*
+	 * References already held by caller and we keep them;
+	 * note that both gc and gcgrp may be set to NULL to
+	 * clear out igsa_gc and igsa_gcgrp, respectively.
+	 */
+	attrp->igsa_gc = gc;
+	attrp->igsa_gcgrp = gcgrp;
+
+	if (gcgrp == NULL && gc != NULL) {
+		gcgrp = gc->gc_grp;
+		ASSERT(gcgrp != NULL);
+	}
+
+	/*
+	 * Intialize the template for gateway; we use the gateway's
+	 * address found in either the passed in gateway credential
+	 * or group pointer, or the ire_gateway_addr{_v6} field.
+	 */
+	if (gcgrp != NULL) {
+		tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
+
+		/*
+		 * Caller is holding a reference, and that we don't
+		 * need to hold any lock to access the address.
+		 */
+		if (ipversion == IPV4_VERSION) {
+			ASSERT(ga->ga_af == AF_INET);
+			IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
+			paddr = &ga_addr4;
+		} else {
+			ASSERT(ga->ga_af == AF_INET6);
+			paddr = &ga->ga_addr;
+		}
+	} else if (ipversion == IPV6_VERSION &&
+	    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
+		paddr = &ire->ire_gateway_addr_v6;
+	} else if (ipversion == IPV4_VERSION &&
+	    ire->ire_gateway_addr != INADDR_ANY) {
+		paddr = &ire->ire_gateway_addr;
+	}
+
+	/*
+	 * Lookup the gateway template; note that we could get an internal
+	 * template here, which we cache anyway.  During IRE matching, we'll
+	 * try to update this gateway template cache and hopefully get a
+	 * real one.
+	 */
+	if (paddr != NULL) {
+		attrp->igsa_rhc = (ipversion == IPV4_VERSION) ?
+		    find_rhc_v4(paddr) : find_rhc_v6(paddr);
+	}
+
+	if (exists)
+		mutex_exit(&attrp->igsa_lock);
+
+	return (0);
+}
+
+/*
+ * This function figures the type of MLP that we'll be using based on the
+ * address that the user is binding and the zone.  If the address is
+ * unspecified, then we're looking at both private and shared.  If it's one
+ * of the zone's private addresses, then it's private only.  If it's one
+ * of the global addresses, then it's shared only.
+ *
+ * If we can't figure out what it is, then return mlptSingle.  That's actually
+ * an error case.
+ */
+mlp_type_t
+tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr)
+{
+	in_addr_t in4;
+	ire_t *ire;
+	ipif_t *ipif;
+	zoneid_t addrzone;
+
+	ASSERT(addr != NULL);
+
+	if (version == IPV6_VERSION &&
+	    IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) {
+		IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4);
+		addr = &in4;
+		version = IPV4_VERSION;
+	}
+
+	if (version == IPV4_VERSION) {
+		in4 = *(const in_addr_t *)addr;
+		if (in4 == INADDR_ANY)
+			return (mlptBoth);
+		ire = ire_cache_lookup(in4, zoneid, NULL);
+	} else {
+		if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr))
+			return (mlptBoth);
+		ire = ire_cache_lookup_v6(addr, zoneid, NULL);
+	}
+	/*
+	 * If we can't find the IRE, then we have to behave exactly like
+	 * ip_bind_laddr{,_v6}.  That means looking up the IPIF so that users
+	 * can bind to addresses on "down" interfaces.
+	 *
+	 * If we can't find that either, then the bind is going to fail, so
+	 * just give up.  Note that there's a miniscule chance that the address
+	 * is in transition, but we don't bother handling that.
+	 */
+	if (ire == NULL) {
+		if (version == IPV4_VERSION)
+			ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL,
+			    zoneid, NULL, NULL, NULL, NULL);
+		else
+			ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr,
+			    NULL, zoneid, NULL, NULL, NULL, NULL);
+		if (ipif == NULL)
+			return (mlptSingle);
+		addrzone = ipif->ipif_zoneid;
+		ipif_refrele(ipif);
+	} else {
+		addrzone = ire->ire_zoneid;
+		ire_refrele(ire);
+	}
+	return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate);
+}
+
+/*
+ * Since we are configuring local interfaces, and we know trusted
+ * extension CDE requires local interfaces to be cipso host type in
+ * order to function correctly, we'll associate a cipso template
+ * to each local interface and let the interface come up.  Configuring
+ * a local interface to be "unlabeled" host type is a configuration error.
+ * We'll override that error and make the interface host type to be cipso
+ * here.
+ *
+ * The code is optimized for the usual "success" case and unwinds things on
+ * error.  We don't want to go to the trouble and expense of formatting the
+ * interface name for the usual case where everything is configured correctly.
+ */
+boolean_t
+tsol_check_interface_address(const ipif_t *ipif)
+{
+	tsol_tpc_t *tp;
+	char addrbuf[INET6_ADDRSTRLEN];
+	int af;
+	const void *addr;
+	zone_t *zone;
+	ts_label_t *plabel;
+	const bslabel_t *label;
+	char ifbuf[LIFNAMSIZ + 10];
+	const char *ifname;
+	boolean_t retval;
+	tsol_rhent_t rhent;
+
+	if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) {
+		af = AF_INET;
+		addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr);
+	} else {
+		af = AF_INET6;
+		addr = &ipif->ipif_v6lcl_addr;
+	}
+
+	tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE);
+	zone = ipif->ipif_zoneid == ALL_ZONES ? NULL :
+	    zone_find_by_id(ipif->ipif_zoneid);
+	if (zone != NULL) {
+		plabel = zone->zone_slabel;
+		ASSERT(plabel != NULL);
+		label = label2bslabel(plabel);
+	}
+
+	/*
+	 * If it's CIPSO and an all-zones address, then we're done.
+	 * If it's a CIPSO zone specific address, the zone's label
+	 * must be in the range or set specified in the template.
+	 * When the remote host entry is missing or the template
+	 * type is incorrect for this interface, we create a
+	 * CIPSO host entry in kernel and allow the interface to be
+	 * brought up as CIPSO type.
+	 */
+	if (tp != NULL && (
+	    /* The all-zones case */
+	    (tp->tpc_tp.host_type == SUN_CIPSO &&
+	    tp->tpc_tp.tp_doi == default_doi &&
+	    ipif->ipif_zoneid == ALL_ZONES) ||
+	    /* The local-zone case */
+	    (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi &&
+	    ((tp->tpc_tp.host_type == SUN_CIPSO &&
+	    (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) ||
+	    blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) {
+		if (zone != NULL)
+			zone_rele(zone);
+		TPC_RELE(tp);
+		return (B_TRUE);
+	}
+
+	ifname = ipif->ipif_ill->ill_name;
+	if (ipif->ipif_id != 0) {
+		(void) snprintf(ifbuf, sizeof (ifbuf), "%s:%u", ifname,
+		    ipif->ipif_id);
+		ifname = ifbuf;
+	}
+	(void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf));
+
+	if (tp == NULL) {
+		cmn_err(CE_NOTE, "template entry for %s missing. Default to "
+		    "CIPSO type for %s", ifname, addrbuf);
+		retval = B_TRUE;
+	} else if (tp->tpc_tp.host_type == UNLABELED) {
+		cmn_err(CE_NOTE, "template type for %s incorrectly configured. "
+		    "Change to CIPSO type for %s", ifname, addrbuf);
+		retval = B_TRUE;
+	} else if (ipif->ipif_zoneid == ALL_ZONES) {
+		if (tp->tpc_tp.host_type != SUN_CIPSO) {
+			cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for "
+			    "all-zones. Converted to CIPSO.", ifname, addrbuf);
+			retval = B_TRUE;
+		} else {
+			cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d "
+			    "instead of %d", ifname, addrbuf,
+			    tp->tpc_tp.tp_doi, default_doi);
+			retval = B_FALSE;
+		}
+	} else if (zone == NULL) {
+		cmn_err(CE_NOTE, "%s failed: zoneid %d unknown",
+		    ifname, ipif->ipif_zoneid);
+		retval = B_FALSE;
+	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
+		cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has "
+		    "DOI %d", ifname, zone->zone_name, plabel->tsl_doi,
+		    addrbuf, tp->tpc_tp.tp_doi);
+		retval = B_FALSE;
+	} else {
+		cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with "
+		    "%s", ifname, zone->zone_name, addrbuf);
+		tsol_print_label(label, "zone label");
+		retval = B_FALSE;
+	}
+
+	if (zone != NULL)
+		zone_rele(zone);
+	if (tp != NULL)
+		TPC_RELE(tp);
+	if (retval) {
+		/*
+		 * we've corrected a config error and let the interface
+		 * come up as cipso. Need to insert an rhent.
+		 */
+		if ((rhent.rh_address.ta_family = af) == AF_INET) {
+			rhent.rh_prefix = 32;
+			rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr;
+		} else {
+			rhent.rh_prefix = 128;
+			rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr;
+		}
+		(void) strcpy(rhent.rh_template, "cipso");
+		if (tnrh_load(&rhent) != 0) {
+			cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO "
+			    "template for local addr %s", ifname, addrbuf);
+			retval = B_FALSE;
+		}
+	}
+	return (retval);
+}
--- a/usr/src/uts/common/inet/ip6.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip6.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -348,26 +347,24 @@
 extern char	*inet_ntop(int, const void *, char *, int);
 extern int	inet_pton(int, char *, void *);
 extern void	icmp_time_exceeded_v6(queue_t *, mblk_t *, uint8_t,
-		    boolean_t, boolean_t);
+    boolean_t, boolean_t);
 extern void	icmp_unreachable_v6(queue_t *, mblk_t *, uint8_t,
-		    boolean_t, boolean_t);
+    boolean_t, boolean_t);
 extern void	icmp_inbound_error_fanout_v6(queue_t *, mblk_t *, ip6_t *,
-		    icmp6_t *, ill_t *, boolean_t, zoneid_t);
+    icmp6_t *, ill_t *, boolean_t, zoneid_t);
 extern boolean_t conn_wantpacket_v6(conn_t *, ill_t *, ip6_t *, int, zoneid_t);
 extern mblk_t	*ip_add_info_v6(mblk_t *, ill_t *, const in6_addr_t *);
 extern in6addr_scope_t	ip_addr_scope_v6(const in6_addr_t *);
 extern mblk_t	*ip_bind_v6(queue_t *, mblk_t *, conn_t *, ip6_pkt_t *);
 extern void	ip_build_hdrs_v6(uchar_t *, uint_t, ip6_pkt_t *, uint8_t);
-extern void	ip_deliver_local_v6(queue_t *, mblk_t *, ill_t *, uint8_t,
-		    uint_t, uint_t);
 extern int	ip_fanout_send_icmp_v6(queue_t *, mblk_t *, uint_t,
-		    uint_t, uint8_t, uint_t, boolean_t, zoneid_t);
+    uint_t, uint8_t, uint_t, boolean_t, zoneid_t);
 extern int	ip_find_hdr_v6(mblk_t *, ip6_t *, ip6_pkt_t *, uint8_t *);
 extern in6_addr_t ip_get_dst_v6(ip6_t *, boolean_t *);
 extern ip6_rthdr_t	*ip_find_rthdr_v6(ip6_t *, uint8_t *);
 extern int	ip_hdr_complete_v6(ip6_t *, zoneid_t);
 extern boolean_t	ip_hdr_length_nexthdr_v6(mblk_t *, ip6_t *,
-		    uint16_t *, uint8_t **);
+    uint16_t *, uint8_t **);
 extern int	ip_hdr_length_v6(mblk_t *, ip6_t *);
 extern uint32_t	ip_massage_options_v6(ip6_t *, ip6_rthdr_t *);
 extern void	ip_wput_frag_v6(mblk_t *, ire_t *, uint_t, conn_t *, int, int);
@@ -376,13 +373,13 @@
 extern int	ip_total_hdrs_len_v6(ip6_pkt_t *);
 extern int	ipsec_ah_get_hdr_size_v6(mblk_t *, boolean_t);
 extern void	ip_wput_local_v6(queue_t *, ill_t *, ip6_t *, mblk_t *,
-		    ire_t *, int);
+    ire_t *, int);
 extern void	ip_wput_md_v6(queue_t *, mblk_t *, conn_t *);
 extern void	ip_output_v6(void *, mblk_t *, void *, int);
 extern void	ip_xmit_v6(mblk_t *, ire_t *, uint_t, conn_t *, int,
-			struct ipsec_out_s *);
+    struct ipsec_out_s *);
 extern void	ip_rput_data_v6(queue_t *, ill_t *, mblk_t *, ip6_t *,
-		    uint_t, mblk_t *);
+    uint_t, mblk_t *);
 extern void	mld_input(queue_t *, mblk_t *, ill_t *);
 extern void	mld_joingroup(ilm_t *);
 extern void	mld_leavegroup(ilm_t *);
@@ -391,15 +388,15 @@
 
 extern void	pr_addr_dbg(char *, int, const void *);
 extern ipif_t	*ip_newroute_get_src_ipif_v6(ipif_t *, boolean_t,
-		const in6_addr_t *);
+    const in6_addr_t *);
 extern int	ip_multirt_apply_membership_v6(int (*fn)(conn_t *, boolean_t,
-		const in6_addr_t *, int, mcast_record_t, const in6_addr_t *,
-		mblk_t *), ire_t *, conn_t *, boolean_t, const in6_addr_t *,
-		mcast_record_t, const in6_addr_t *, mblk_t *);
+    const in6_addr_t *, int, mcast_record_t, const in6_addr_t *,
+    mblk_t *), ire_t *, conn_t *, boolean_t, const in6_addr_t *,
+    mcast_record_t, const in6_addr_t *, mblk_t *);
 extern void	ip_newroute_ipif_v6(queue_t *, mblk_t *, ipif_t *,
-		in6_addr_t, int, zoneid_t);
+    in6_addr_t, int, zoneid_t);
 extern void	ip_newroute_v6(queue_t *, mblk_t *, const in6_addr_t *,
-		const in6_addr_t *, ill_t *, zoneid_t);
+    const in6_addr_t *, ill_t *, zoneid_t);
 extern void	ip6_kstat_init(void);
 extern size_t	ip6_get_src_preferences(conn_t *, uint32_t *);
 extern int	ip6_set_src_preferences(conn_t *, uint32_t);
--- a/usr/src/uts/common/inet/ip_if.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip_if.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -30,6 +29,8 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
+#include <net/route.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -151,7 +152,7 @@
 extern	void	ill_delete(ill_t *);
 extern	void	ill_delete_tail(ill_t *);
 extern	int	ill_dl_phys(ill_t *, ipif_t *, mblk_t *, queue_t *);
-extern	int	ill_dls_info(struct sockaddr_dl *, ipif_t *);
+extern	int	ill_dls_info(struct sockaddr_dl *, const ipif_t *);
 extern	void	ill_fastpath_ack(ill_t *, mblk_t *);
 extern	void	ill_fastpath_nack(ill_t *);
 extern	int	ill_fastpath_probe(ill_t *, mblk_t *);
@@ -186,7 +187,7 @@
 extern int	ill_up_ipifs(ill_t *, queue_t *, mblk_t *);
 extern	boolean_t ill_is_probeonly(ill_t *);
 
-extern	char	*ipif_get_name(ipif_t *, char *, int);
+extern	char	*ipif_get_name(const ipif_t *, char *, int);
 extern	void	ipif_init(void);
 extern	ipif_t	*ipif_lookup_addr(ipaddr_t, ill_t *, zoneid_t, queue_t *,
     mblk_t *, ipsq_func_t, int *);
@@ -255,13 +256,15 @@
 extern	int	ip_ill_report(queue_t *, mblk_t *, caddr_t, cred_t *);
 extern	int	ip_ipif_report(queue_t *, mblk_t *, caddr_t, cred_t *);
 extern	void	ip_ll_subnet_defaults(ill_t *, mblk_t *);
+
 extern	int	ip_rt_add(ipaddr_t, ipaddr_t, ipaddr_t, ipaddr_t, int,
-    ipif_t *, ipif_t *, ire_t **, boolean_t, queue_t *, mblk_t *, ipsq_func_t);
+    ipif_t *, ipif_t *, ire_t **, boolean_t, queue_t *, mblk_t *, ipsq_func_t,
+    struct rtsa_s *);
 extern	int	ip_mrtun_rt_add(ipaddr_t, int, ipif_t *, ipif_t *, ire_t **,
     queue_t *, mblk_t *, ipsq_func_t);
 extern	int	ip_rt_add_v6(const in6_addr_t *, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, int, ipif_t *, ire_t **,
-    queue_t *, mblk_t *, ipsq_func_t);
+    queue_t *, mblk_t *, ipsq_func_t, struct rtsa_s *);
 extern	int	ip_rt_delete(ipaddr_t, ipaddr_t, ipaddr_t, uint_t, int,
     ipif_t *, ipif_t *, boolean_t, queue_t *, mblk_t *, ipsq_func_t);
 extern	int	ip_mrtun_rt_delete(ipaddr_t, ipif_t *);
--- a/usr/src/uts/common/inet/ip_ire.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip_ire.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -128,6 +127,7 @@
 					/* zones or shared IREs */
 #define	MATCH_IRE_MARK_PRIVATE_ADDR	0x8000	/* Match IRE ire_marks with */
 						/* IRE_MARK_PRIVATE_ADDR. */
+#define	MATCH_IRE_SECATTR	0x10000	/* Match gateway security attributes */
 
 /* Structure for ire_cache_count() */
 typedef struct {
@@ -176,6 +176,8 @@
 extern uint_t ire_srcif_table_count;
 
 #ifdef _KERNEL
+struct ts_label_s;
+
 extern	ipaddr_t	ip_plen_to_mask(uint_t);
 extern	in6_addr_t	*ip_plen_to_mask_v6(uint_t, in6_addr_t *);
 
@@ -194,8 +196,8 @@
 extern	int	ip_mask_to_plen(ipaddr_t);
 extern	int	ip_mask_to_plen_v6(const in6_addr_t *);
 
-extern	ire_t	*ipif_to_ire(ipif_t *);
-extern	ire_t	*ipif_to_ire_v6(ipif_t *);
+extern	ire_t	*ipif_to_ire(const ipif_t *);
+extern	ire_t	*ipif_to_ire_v6(const ipif_t *);
 
 extern	int	ire_add(ire_t **, queue_t *, mblk_t *, ipsq_func_t);
 extern	int	ire_add_mrtun(ire_t **, queue_t *, mblk_t *, ipsq_func_t);
@@ -206,19 +208,24 @@
 extern	void	ire_atomic_end(irb_t *irb_ptr, ire_t *ire);
 
 extern	void	ire_cache_count(ire_t *, char *);
-extern	ire_t	*ire_cache_lookup(ipaddr_t, zoneid_t);
-extern	ire_t	*ire_cache_lookup_v6(const in6_addr_t *, zoneid_t);
+extern	ire_t	*ire_cache_lookup(ipaddr_t, zoneid_t,
+    const struct ts_label_s *);
+extern	ire_t	*ire_cache_lookup_v6(const in6_addr_t *, zoneid_t,
+    const struct ts_label_s *);
 extern	void	ire_cache_reclaim(ire_t *, char *);
 
 extern	void	ire_check_bcast_present(ipif_t *, ipaddr_t, int, boolean_t *,
     boolean_t *);
+
 extern	ire_t	*ire_create_mp(uchar_t *, uchar_t *, uchar_t *, uchar_t *,
     uchar_t *, uint_t, mblk_t *, queue_t *, queue_t *, ushort_t, mblk_t *,
-    ipif_t *, ill_t *, ipaddr_t, uint32_t, uint32_t, uint32_t, const iulp_t *);
+    ipif_t *, ill_t *, ipaddr_t, uint32_t, uint32_t, uint32_t, const iulp_t *,
+    tsol_gc_t *, tsol_gcgrp_t *);
 
 extern	ire_t	*ire_create(uchar_t *, uchar_t *, uchar_t *, uchar_t *,
     uchar_t *, uint_t *, mblk_t *, queue_t *, queue_t *, ushort_t, mblk_t *,
-    ipif_t *, ill_t *, ipaddr_t, uint32_t, uint32_t, uint32_t, const iulp_t *);
+    ipif_t *, ill_t *, ipaddr_t, uint32_t, uint32_t, uint32_t, const iulp_t *,
+    tsol_gc_t *, tsol_gcgrp_t *);
 
 extern	ire_t	**ire_check_and_create_bcast(ipif_t *, ipaddr_t,
     ire_t **, int);
@@ -226,32 +233,38 @@
 extern	ire_t	*ire_init(ire_t *, uchar_t *, uchar_t *, uchar_t *,
     uchar_t *, uchar_t *, uint_t *, mblk_t *, queue_t *, queue_t *, ushort_t,
     mblk_t *, ipif_t *, ill_t *, ipaddr_t, uint32_t, uint32_t, uint32_t,
-    const iulp_t *);
+    const iulp_t *, tsol_gc_t *, tsol_gcgrp_t *);
 
-extern	void	ire_init_common(ire_t *, uint_t *, mblk_t *, queue_t *,
+extern	boolean_t ire_init_common(ire_t *, uint_t *, mblk_t *, queue_t *,
     queue_t *, ushort_t, mblk_t *, ipif_t *, ill_t *, uint32_t,
-    uint32_t, uint32_t, uchar_t, const iulp_t *);
+    uint32_t, uint32_t, uchar_t, const iulp_t *, tsol_gc_t *, tsol_gcgrp_t *);
 
 extern	ire_t	*ire_create_v6(const in6_addr_t *, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, uint_t *, mblk_t *, queue_t *,
     queue_t *, ushort_t, mblk_t *, ipif_t *,
-    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *);
+    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *,
+    tsol_gc_t *, tsol_gcgrp_t *);
 
 extern	ire_t	*ire_create_mp_v6(const in6_addr_t *, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, mblk_t *, queue_t *,
     queue_t *, ushort_t, mblk_t *, ipif_t *,
-    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *);
+    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *,
+    tsol_gc_t *, tsol_gcgrp_t *);
 
 extern	ire_t	*ire_init_v6(ire_t *, const in6_addr_t *, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, uint_t *, mblk_t *, queue_t *,
     queue_t *, ushort_t, mblk_t *, ipif_t *,
-    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *);
+    const in6_addr_t *, uint32_t, uint32_t, uint_t, const iulp_t *,
+    tsol_gc_t *, tsol_gcgrp_t *);
 
-extern	ire_t	*ire_ctable_lookup(ipaddr_t, ipaddr_t, int, ipif_t *,
-    zoneid_t, int);
+extern	void	ire_clookup_delete_cache_gw(ipaddr_t, zoneid_t);
+extern	void	ire_clookup_delete_cache_gw_v6(const in6_addr_t *, zoneid_t);
+
+extern	ire_t	*ire_ctable_lookup(ipaddr_t, ipaddr_t, int, const ipif_t *,
+    zoneid_t, const struct ts_label_s *, int);
 
 extern	ire_t	*ire_ctable_lookup_v6(const in6_addr_t *, const in6_addr_t *,
-    int, ipif_t *, zoneid_t, int);
+    int, const ipif_t *, zoneid_t, const struct ts_label_s *, int);
 
 extern	void	ire_delete(ire_t *);
 extern	void	ire_delete_cache_gw(ire_t *, char *);
@@ -267,11 +280,13 @@
 extern	void	ire_flush_cache_v4(ire_t *, int);
 extern	void	ire_flush_cache_v6(ire_t *, int);
 
-extern	ire_t	*ire_ftable_lookup(ipaddr_t, ipaddr_t, ipaddr_t, int, ipif_t *,
-    ire_t **, zoneid_t, uint32_t, int);
+extern	ire_t	*ire_ftable_lookup(ipaddr_t, ipaddr_t, ipaddr_t, int,
+    const ipif_t *, ire_t **, zoneid_t, uint32_t,
+    const struct ts_label_s *, int);
 
 extern	ire_t	*ire_ftable_lookup_v6(const in6_addr_t *, const in6_addr_t *,
-    const in6_addr_t *, int, ipif_t *, ire_t **, zoneid_t, uint32_t, int);
+    const in6_addr_t *, int, const ipif_t *, ire_t **, zoneid_t,
+    uint32_t, const struct ts_label_s *, int);
 
 extern	ire_t	*ire_ihandle_lookup_onlink(ire_t *);
 extern	ire_t	*ire_ihandle_lookup_offlink(ire_t *, ire_t *);
@@ -287,28 +302,33 @@
 
 extern	void	ire_refrele(ire_t *);
 extern	void	ire_refrele_notr(ire_t *);
-extern	ire_t	*ire_route_lookup(ipaddr_t, ipaddr_t, ipaddr_t, int, ipif_t *,
-    ire_t **, zoneid_t, int);
+extern	ire_t	*ire_route_lookup(ipaddr_t, ipaddr_t, ipaddr_t, int,
+    const ipif_t *, ire_t **, zoneid_t, const struct ts_label_s *, int);
 
 extern	ire_t	*ire_route_lookup_v6(const in6_addr_t *, const in6_addr_t *,
-    const in6_addr_t *, int, ipif_t *, ire_t **, zoneid_t, int);
+    const in6_addr_t *, int, const ipif_t *, ire_t **, zoneid_t,
+    const struct ts_label_s *, int);
 
 extern	ire_t	*ire_srcif_table_lookup(ipaddr_t, int, ipif_t *, ill_t *, int);
-extern ill_t	*ire_to_ill(ire_t *);
+extern ill_t	*ire_to_ill(const ire_t *);
 
-extern	void	ire_walk(pfv_t, char *);
-extern	void	ire_walk_ill(uint_t, uint_t, pfv_t, char *, ill_t *);
+extern	void	ire_walk(pfv_t, void *);
+extern	void	ire_walk_ill(uint_t, uint_t, pfv_t, void *, ill_t *);
 extern	void	ire_walk_ill_mrtun(uint_t, uint_t, pfv_t, void *, ill_t *);
-extern	void	ire_walk_ill_v4(uint_t, uint_t, pfv_t, char *, ill_t *);
-extern	void	ire_walk_ill_v6(uint_t, uint_t, pfv_t, char *, ill_t *);
-extern	void	ire_walk_v4(pfv_t, char *, zoneid_t);
-extern	void	ire_walk_srcif_table_v4(pfv_t, char *);
-extern	void	ire_walk_v6(pfv_t, char *, zoneid_t);
+extern	void	ire_walk_ill_v4(uint_t, uint_t, pfv_t, void *, ill_t *);
+extern	void	ire_walk_ill_v6(uint_t, uint_t, pfv_t, void *, ill_t *);
+extern	void	ire_walk_v4(pfv_t, void *, zoneid_t);
+extern	void	ire_walk_srcif_table_v4(pfv_t, void *);
+extern	void	ire_walk_v6(pfv_t, void *, zoneid_t);
 
-extern boolean_t	ire_multirt_lookup(ire_t **, ire_t **, uint32_t);
-extern boolean_t	ire_multirt_need_resolve(ipaddr_t);
-extern boolean_t	ire_multirt_lookup_v6(ire_t **, ire_t **, uint32_t);
-extern boolean_t	ire_multirt_need_resolve_v6(const in6_addr_t *);
+extern boolean_t	ire_multirt_lookup(ire_t **, ire_t **, uint32_t,
+    const struct ts_label_s *);
+extern boolean_t	ire_multirt_need_resolve(ipaddr_t,
+    const struct ts_label_s *);
+extern boolean_t	ire_multirt_lookup_v6(ire_t **, ire_t **, uint32_t,
+    const struct ts_label_s *);
+extern boolean_t	ire_multirt_need_resolve_v6(const in6_addr_t *,
+    const struct ts_label_s *);
 
 extern ire_t	*ipif_lookup_multi_ire(ipif_t *, ipaddr_t);
 extern ire_t	*ipif_lookup_multi_ire_v6(ipif_t *, const in6_addr_t *);
--- a/usr/src/uts/common/inet/ip_ndp.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip_ndp.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -269,8 +268,8 @@
 extern	int	ndp_sioc_update(ill_t *, lif_nd_req_t *);
 extern	boolean_t	ndp_verify_optlen(nd_opt_hdr_t *, int);
 extern	void	ndp_timer(void *);
-extern	void	ndp_walk(ill_t *, pfi_t, uchar_t *);
-extern	void	ndp_walk_impl(ill_t *, pfi_t, uchar_t *, boolean_t);
+extern	void	ndp_walk(ill_t *, pfi_t, void *);
+extern	void	ndp_walk_impl(ill_t *, pfi_t, void *, boolean_t);
 extern	int	ndp_add(ill_t *, uchar_t *, const in6_addr_t *,
 		    const in6_addr_t *, const in6_addr_t *,
 		    uint32_t, uint16_t, uint16_t, nce_t **);
--- a/usr/src/uts/common/inet/ip_rts.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ip_rts.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1992-2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,6 +32,13 @@
 extern "C" {
 #endif
 
+/*
+ * Maximum number of route security attributes that can be
+ * configured per route destination through the routing
+ * socket message.
+ */
+#define	TSOL_RTSA_REQUEST_MAX	1	/* one per route destination */
+
 #ifdef _KERNEL
 extern	void	ip_rts_change(int, ipaddr_t, ipaddr_t,
     ipaddr_t, ipaddr_t, ipaddr_t, int, int,
@@ -41,21 +47,22 @@
 extern	void	ip_rts_change_v6(int, const in6_addr_t *, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, const in6_addr_t *, int, int, int);
 
-extern	void	ip_rts_ifmsg(ipif_t *);
+extern	void	ip_rts_ifmsg(const ipif_t *);
 
-extern	void	ip_rts_newaddrmsg(int, int, ipif_t *);
+extern	void	ip_rts_newaddrmsg(int, int, const ipif_t *);
 
 extern	int	ip_rts_request(queue_t *, mblk_t *, cred_t *);
 
 extern	void	ip_rts_rtmsg(int, ire_t *, int);
 
-extern	mblk_t	*rts_alloc_msg(int, int, sa_family_t);
+extern	mblk_t	*rts_alloc_msg(int, int, sa_family_t, uint_t);
 
-extern	size_t	rts_data_msg_size(int, sa_family_t);
+extern	size_t	rts_data_msg_size(int, sa_family_t, uint_t);
 
 extern	void	rts_fill_msg_v6(int, int, const in6_addr_t *,
     const in6_addr_t *, const in6_addr_t *, const in6_addr_t *,
-    const in6_addr_t *, const in6_addr_t *, ipif_t *, mblk_t *);
+    const in6_addr_t *, const in6_addr_t *, const ipif_t *, mblk_t *,
+    uint_t, const tsol_gc_t *);
 
 extern	size_t	rts_header_msg_size(int);
 
--- a/usr/src/uts/common/inet/ipclassifier.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/ipclassifier.h	Fri Mar 24 12:29:20 2006 -0800
@@ -137,30 +137,32 @@
 		conn_dontroute : 1,		/* SO_DONTROUTE state */
 		conn_loopback : 1,		/* SO_LOOPBACK state */
 		conn_broadcast : 1,		/* SO_BROADCAST state */
+
 		conn_reuseaddr : 1,		/* SO_REUSEADDR state */
-
 		conn_multicast_loop : 1,	/* IP_MULTICAST_LOOP */
 		conn_multi_router : 1,		/* Wants all multicast pkts */
 		conn_draining : 1,		/* ip_wsrv running */
+
 		conn_did_putbq : 1,		/* ip_wput did a putbq */
-
 		conn_unspec_src : 1,		/* IP_UNSPEC_SRC */
 		conn_policy_cached : 1,		/* Is policy cached/latched ? */
 		conn_in_enforce_policy : 1,	/* Enforce Policy on inbound */
+
 		conn_out_enforce_policy : 1,	/* Enforce Policy on outbound */
-
 		conn_af_isv6 : 1,		/* ip address family ver 6 */
 		conn_pkt_isv6 : 1,		/* ip packet format ver 6 */
 		conn_ipv6_recvpktinfo : 1,	/* IPV6_RECVPKTINFO option */
+
 		conn_ipv6_recvhoplimit : 1,	/* IPV6_RECVHOPLIMIT option */
-
 		conn_ipv6_recvhopopts : 1,	/* IPV6_RECVHOPOPTS option */
 		conn_ipv6_recvdstopts : 1,	/* IPV6_RECVDSTOPTS option */
 		conn_ipv6_recvrthdr : 1,	/* IPV6_RECVRTHDR option */
+
 		conn_ipv6_recvrtdstopts : 1,	/* IPV6_RECVRTHDRDSTOPTS */
 		conn_ipv6_v6only : 1,		/* IPV6_V6ONLY */
 		conn_ipv6_recvtclass : 1,	/* IPV6_RECVTCLASS */
 		conn_ipv6_recvpathmtu : 1,	/* IPV6_RECVPATHMTU */
+
 		conn_pathmtu_valid : 1,		/* The cached mtu is valid. */
 		conn_ipv6_dontfrag : 1,		/* IPV6_DONTFRAG */
 		/*
@@ -170,6 +172,7 @@
 		 */
 		conn_fully_bound : 1,		/* Fully bound connection */
 		conn_recvif : 1,		/* IP_RECVIF option */
+
 		conn_recvslla : 1,		/* IP_RECVSLLA option */
 		conn_mdt_ok : 1,		/* MDT is permitted */
 		conn_nexthop_set : 1,
@@ -258,6 +261,17 @@
 	zoneid_t	conn_zoneid;		/* zone connection is in */
 	in6_addr_t	conn_nexthop_v6;	/* nexthop IP address */
 #define	conn_nexthop_v4	V4_PART_OF_V6(conn_nexthop_v6)
+	cred_t		*conn_peercred;		/* Peer credentials, if any */
+
+	unsigned int
+		conn_ulp_labeled : 1,		/* ULP label is synced */
+		conn_mlp_type : 2,		/* mlp_type_t; tsol/tndb.h */
+		conn_anon_mlp : 1,		/* user wants anon MLP */
+
+		conn_anon_port : 1,		/* user bound anonymously */
+		conn_mac_exempt : 1,		/* unlabeled with loose MAC */
+		conn_spare : 26;
+
 #ifdef CONN_DEBUG
 #define	CONN_TRACE_MAX	10
 	int		conn_trace_last;	/* ndx of last used tracebuf */
@@ -265,6 +279,11 @@
 #endif
 };
 
+#define	CONN_CRED(connp) ((connp)->conn_peercred == NULL ? \
+	(connp)->conn_cred : (connp)->conn_peercred)
+#define	BEST_CRED(mp, connp) ((DB_CRED(mp) != NULL &&	\
+	crgetlabel(DB_CRED(mp)) != NULL) ? DB_CRED(mp) : CONN_CRED(connp))
+
 /*
  * connf_t - connection fanout data.
  *
@@ -330,7 +349,7 @@
 	(((connp)->conn_src == ((ipha)->ipha_dst)) &&			\
 	(((connp)->conn_rem == INADDR_ANY) ||				\
 	((connp)->conn_rem == ((ipha)->ipha_src))))) &&			\
-	((connp)->conn_zoneid == (zoneid)) &&				\
+	((zoneid) == ALL_ZONES || (connp)->conn_zoneid == (zoneid)) &&	\
 	(conn_wantpacket((connp), (ill), (ipha),			\
 	(fanout_flags), (zoneid)) || ((protocol) == IPPROTO_PIM) ||	\
 	((protocol) == IPPROTO_RSVP)))
@@ -499,7 +518,7 @@
 conn_t *ipcl_classify_v4(mblk_t *, uint8_t, uint_t, zoneid_t);
 conn_t *ipcl_classify_v6(mblk_t *, uint8_t, uint_t, zoneid_t);
 conn_t *ipcl_classify(mblk_t *, zoneid_t);
-conn_t *ipcl_classify_raw(uint8_t, zoneid_t, uint32_t, ipha_t *);
+conn_t *ipcl_classify_raw(mblk_t *, uint8_t, zoneid_t, uint32_t, ipha_t *);
 void	ipcl_globalhash_insert(conn_t *);
 void	ipcl_globalhash_remove(conn_t *);
 void	ipcl_walk(pfv_t, void *);
--- a/usr/src/uts/common/inet/mib2.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/mib2.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -31,6 +30,8 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <netinet/in.h>	/* For in6_addr_t */
+#include <sys/tsol/label.h> /* For brange_t */
+#include <sys/tsol/label_macro.h> /* For brange_t */
 
 #ifdef	__cplusplus
 extern "C" {
@@ -161,6 +162,12 @@
 #define	EXPER_IP6_GROUP_MEMBERSHIP	101
 #define	EXPER_IP_GROUP_SOURCES		102
 #define	EXPER_IP6_GROUP_SOURCES		103
+#define	EXPER_IP_RTATTR			104
+
+/*
+ * There can be one of each of these tables per transport (MIB2_* above).
+ */
+#define	EXPER_XPORT_MLP		105	/* transportMLPEntry */
 
 /* Old names retained for compatibility */
 #define	MIB2_IP_20	MIB2_IP_ADDR
@@ -259,6 +266,9 @@
 	Counter ipOutIPv6;
 		/* # of times ip_wput has switched to become ip_wput_v6 */
 	Counter ipOutSwitchIPv6;
+
+	int	ipRouteAttributeSize;	/* Size of mib2_ipAttributeEntry_t */
+	int	transportMLPSize;	/* Size of mib2_transportMLPEntry_t */
 } mib2_ip_t;
 
 /*
@@ -447,7 +457,6 @@
 	}		ipv6AddrInfo;
 } mib2_ipv6AddrEntry_t;
 
-
 /*
  * The IP routing table contains an entry for each route presently known to
  * this entity. (for IPv4 routes)
@@ -562,6 +571,44 @@
 	} 		ipv6RouteInfo;
 } mib2_ipv6RouteEntry_t;
 
+/*
+ * The IPv4 and IPv6 routing table entries on a trusted system also have
+ * security attributes in the form of label ranges.  This experimental
+ * interface provides information about these labels.
+ *
+ * Each entry in this table contains a label range and an index that refers
+ * back to the entry in the routing table to which it applies.  There may be 0,
+ * 1, or many label ranges for each routing table entry.
+ *
+ * (opthdr.level is set to MIB2_IP for IPv4 entries and MIB2_IP6 for IPv6.
+ * opthdr.name is set to EXPER_IP_GWATTR.)
+ *
+ *	ipRouteAttributeTable OBJECT-TYPE
+ *		SYNTAX  SEQUENCE OF IpAttributeEntry
+ *		ACCESS  not-accessible
+ *		STATUS  current
+ *		DESCRIPTION
+ *			"IPv4 routing attributes table.  This table contains
+ *			an entry for each valid trusted label attached to a
+ *			route in the system."
+ *		::= { ip 102 }
+ *
+ *	ipv6RouteAttributeTable OBJECT-TYPE
+ *		SYNTAX  SEQUENCE OF IpAttributeEntry
+ *		ACCESS  not-accessible
+ *		STATUS  current
+ *		DESCRIPTION
+ *			"IPv6 routing attributes table.  This table contains
+ *			an entry for each valid trusted label attached to a
+ *			route in the system."
+ *		::= { ip6 102 }
+ */
+
+typedef struct mib2_ipAttributeEntry {
+	uint_t		iae_routeidx;
+	int		iae_doi;
+	brange_t	iae_slrange;
+} mib2_ipAttributeEntry_t;
 
 /*
  * The IP address translation table contain the IpAddress to
@@ -670,6 +717,26 @@
 	int		ipv6GroupMemberFilterMode;
 } ipv6_member_t;
 
+/*
+ * This is used to mark transport layer entities (e.g., TCP connections) that
+ * are capable of receiving packets from a range of labels.  'level' is set to
+ * the protocol of interest (e.g., MIB2_TCP), and 'name' is set to
+ * EXPER_XPORT_MLP.  The tme_connidx refers back to the entry in MIB2_TCP_CONN,
+ * MIB2_TCP6_CONN, or MIB2_SCTP_CONN.
+ *
+ * It is also used to report connections that receive packets at a single label
+ * that's other than the zone's label.  This is the case when a TCP connection
+ * is accepted from a particular peer using an MLP listener.
+ */
+typedef struct mib2_transportMLPEntry {
+	uint_t		tme_connidx;
+	uint_t		tme_flags;
+	int		tme_doi;
+	bslabel_t	tme_label;
+} mib2_transportMLPEntry_t;
+
+#define	MIB2_TMEF_PRIVATE	0x00000001	/* MLP on private addresses */
+#define	MIB2_TMEF_SHARED	0x00000002	/* MLP on shared addresses */
 
 /*
  * List of IPv4 source addresses being filtered per interface
--- a/usr/src/uts/common/inet/nd.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/nd.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1992, 1997-2001, 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -31,6 +30,8 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/types.h>
+#include <inet/common.h>
+#include <inet/led.h>
 
 #ifdef	__cplusplus
 extern "C" {
--- a/usr/src/uts/common/inet/optcom.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/optcom.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -34,15 +33,12 @@
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <sys/stropts.h>
-#include <sys/strlog.h>
 #include <sys/strsubr.h>
 #include <sys/errno.h>
 #define	_SUN_TPI_VERSION 2
 #include <sys/tihdr.h>
-#include <sys/timod.h>
 #include <sys/socket.h>
 #include <sys/ddi.h>
-#include <sys/cmn_err.h>
 #include <sys/debug.h>		/* for ASSERT */
 #include <sys/policy.h>
 
@@ -53,8 +49,6 @@
 #include <inet/ip.h>
 #include <inet/mib2.h>
 #include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netinet/ip_mroute.h>
 #include "optcom.h"
 
 #include <inet/optcom.h>
@@ -2229,3 +2223,76 @@
 	}
 	return (B_FALSE);
 }
+
+/*
+ * This routine appends a pssed in hop-by-hop option to the existing
+ * option (in this case a cipso label encoded in HOPOPT option). The
+ * passed in option is always padded. The 'reservelen' is the
+ * length of reserved data (label). New memory will be allocated if
+ * the current buffer is not large enough. Return failure if memory
+ * can not be allocated.
+ */
+int
+optcom_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky,
+    uchar_t **optbufp, uint_t *optlenp, uint_t reservelen)
+{
+	uchar_t *optbuf;
+	uchar_t	*optp;
+
+	if (!sticky) {
+		*optbufp = invalp;
+		*optlenp = inlen;
+		return (0);
+	}
+
+	if (inlen == *optlenp - reservelen) {
+		/* Unchanged length - no need to reallocate */
+		optp = *optbufp + reservelen;
+		bcopy(invalp, optp, inlen);
+		if (reservelen != 0) {
+			/*
+			 * Convert the NextHeader and Length of the
+			 * passed in hop-by-hop header to pads
+			 */
+			optp[0] = IP6OPT_PADN;
+			optp[1] = 0;
+		}
+		return (0);
+	}
+	if (inlen + reservelen > 0) {
+		/* Allocate new buffer before free */
+		optbuf = kmem_alloc(inlen + reservelen, KM_NOSLEEP);
+		if (optbuf == NULL)
+			return (ENOMEM);
+	} else {
+		optbuf = NULL;
+	}
+
+	/* Copy out old reserved data (label) */
+	if (reservelen > 0)
+		bcopy(*optbufp, optbuf, reservelen);
+
+	/* Free old buffer */
+	if (*optlenp != 0)
+		kmem_free(*optbufp, *optlenp);
+
+	if (inlen > 0)
+		bcopy(invalp, optbuf + reservelen, inlen);
+
+	if (reservelen != 0) {
+		/*
+		 * Convert the NextHeader and Length of the
+		 * passed in hop-by-hop header to pads
+		 */
+		optbuf[reservelen] = IP6OPT_PADN;
+		optbuf[reservelen + 1] = 0;
+		/*
+		 * Set the Length of the hop-by-hop header, number of 8
+		 * byte-words following the 1st 8 bytes
+		 */
+		optbuf[1] = (reservelen + inlen - 1) >> 3;
+	}
+	*optbufp = optbuf;
+	*optlenp = inlen + reservelen;
+	return (0);
+}
--- a/usr/src/uts/common/inet/optcom.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/optcom.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -225,6 +224,8 @@
 extern int  tpi_optcom_buf(queue_t *, mblk_t *, t_scalar_t *, t_scalar_t,
     cred_t *, optdb_obj_t *, void *, int *);
 extern t_uscalar_t optcom_max_optsize(opdes_t *, uint_t);
+extern int optcom_pkt_set(uchar_t *, uint_t, boolean_t, uchar_t **, uint_t *,
+    uint_t);
 
 #endif	/* defined(_KERNEL) && defined(__STDC__) */
 
--- a/usr/src/uts/common/inet/rawip_impl.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/rawip_impl.h	Fri Mar 24 12:29:20 2006 -0800
@@ -98,8 +98,9 @@
 	    icmp_ipv6_recvrtdstopts : 1, /* Obsolete IPV6_RECVRTHDRDSTOPTS */
 	    icmp_old_ipv6_recvdstopts : 1, /* Old ver of IPV6_RECVDSTOPTS */
 	    icmp_timestamp : 1,  	/* SO_TIMESTAMP "socket" option */
+	    icmp_mac_exempt : 1,	/* SO_MAC_EXEMPT option */
 
-	    icmp_pad_to_bit_31: 8;
+	    icmp_pad_to_bit_31: 7;
 
 	uint8_t		icmp_type_of_service;
 	uint8_t		icmp_ttl;		/* TTL or hoplimit */
@@ -111,6 +112,10 @@
 	uint8_t		*icmp_sticky_hdrs;	/* Prebuilt IPv6 hdrs */
 	uint_t		icmp_sticky_hdrs_len;	/* Incl. ip6h and any ip6i */
 	zoneid_t	icmp_zoneid;		/* ID of owning zone */
+	uint_t		icmp_label_len;		/* length of security label */
+	uint_t		icmp_label_len_v6;	/* sec. part of sticky opt */
+	in6_addr_t 	icmp_v6lastdst;		/* most recent destination */
+	mblk_t		*icmp_delabel;		/* send this on close */
 } icmp_t;
 
 #endif	/* _KERNEL */
--- a/usr/src/uts/common/inet/sctp/sctp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -42,6 +42,7 @@
 #include <sys/kmem.h>
 #include <sys/cpuvar.h>
 #include <sys/random.h>
+#include <sys/priv.h>
 
 #include <sys/errno.h>
 #include <sys/signal.h>
@@ -80,7 +81,6 @@
 
 static void	sctp_closei_local(sctp_t *sctp);
 static int	sctp_init_values(sctp_t *, sctp_t *, int);
-void		sctp_display_all();
 static void	sctp_icmp_error_ipv6(sctp_t *sctp, mblk_t *mp);
 static void	sctp_process_recvq(void *);
 static void	sctp_rq_tq_init(void);
@@ -89,7 +89,6 @@
 static void	sctp_conn_cache_fini();
 static int	sctp_conn_cache_constructor();
 static void	sctp_conn_cache_destructor();
-void		sctp_inc_taskq(void);
 
 /*
  * SCTP receive queue taskq
@@ -192,9 +191,13 @@
 	sctp_t	*sctp;
 	mblk_t	*ack_mp, *hb_mp;
 	conn_t	*connp, *pconnp;
+	cred_t *credp;
 
 	if ((connp = ipcl_conn_create(IPCL_SCTPCONN, KM_NOSLEEP)) == NULL)
 		return (NULL);
+
+	connp->conn_ulp_labeled = is_system_labeled();
+
 	sctp = CONN2SCTP(connp);
 
 	if ((ack_mp = sctp_timer_alloc(sctp, sctp_ack_timer)) == NULL ||
@@ -221,9 +224,20 @@
 		kmem_cache_free(sctp_conn_cache, connp);
 		return (NULL);
 	}
-	if (pconnp->conn_cred != NULL) {
-		connp->conn_cred = pconnp->conn_cred;
-		crhold(connp->conn_cred);
+
+	/*
+	 * If the parent is multilevel, then we'll fix up the remote cred
+	 * when we do sctp_accept_comm.
+	 */
+	if ((credp = pconnp->conn_cred) != NULL) {
+		connp->conn_cred = credp;
+		crhold(credp);
+		/*
+		 * If the caller has the process-wide flag set, then default to
+		 * MAC exempt mode.  This allows read-down to unlabeled hosts.
+		 */
+		if (getpflags(NET_MAC_AWARE, credp) != 0)
+			connp->conn_mac_exempt = B_TRUE;
 	}
 	connp->conn_zoneid = psctp->sctp_zoneid;
 	sctp->sctp_mss = psctp->sctp_mss;
@@ -250,7 +264,8 @@
 	    (sctp->sctp_ipversion == IPV4_VERSION ||
 	    sctp->sctp_ipversion == IPV6_VERSION)));
 
-	dprint(3, ("sctp_clean_death %p, state %d\n", sctp, sctp->sctp_state));
+	dprint(3, ("sctp_clean_death %p, state %d\n", (void *)sctp,
+	    sctp->sctp_state));
 
 	sctp->sctp_client_errno = err;
 	/*
@@ -311,7 +326,8 @@
 	int	error = 0;
 	sctp_faddr_t *fp;
 
-	dprint(3, ("sctp_disconnect %p, state %d\n", sctp, sctp->sctp_state));
+	dprint(3, ("sctp_disconnect %p, state %d\n", (void *)sctp,
+	    sctp->sctp_state));
 
 	RUN_SCTP(sctp);
 
@@ -421,7 +437,8 @@
 void
 sctp_close(sctp_t *sctp)
 {
-	dprint(3, ("sctp_close %p, state %d\n", sctp, sctp->sctp_state));
+	dprint(3, ("sctp_close %p, state %d\n", (void *)sctp,
+	    sctp->sctp_state));
 
 	RUN_SCTP(sctp);
 	sctp->sctp_detached = 1;
@@ -630,7 +647,6 @@
 sctp_free(conn_t *connp)
 {
 	sctp_t *sctp = CONN2SCTP(connp);
-	ip6_pkt_t	*ipp;
 	int		cnt;
 
 	/* Unlink it from the global list */
@@ -692,26 +708,7 @@
 		list_destroy(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
 	}
 
-	ipp = &sctp->sctp_sticky_ipp;
-	if (ipp->ipp_rthdrlen != 0) {
-		kmem_free(ipp->ipp_rthdr, ipp->ipp_rthdrlen);
-		ipp->ipp_rthdrlen = 0;
-	}
-
-	if (ipp->ipp_dstoptslen != 0) {
-		kmem_free(ipp->ipp_dstopts, ipp->ipp_dstoptslen);
-		ipp->ipp_dstoptslen = 0;
-	}
-
-	if (ipp->ipp_rtdstoptslen != 0) {
-		kmem_free(ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen);
-		ipp->ipp_rtdstoptslen = 0;
-	}
-
-	if (ipp->ipp_hopoptslen != 0) {
-		kmem_free(ipp->ipp_hopopts, ipp->ipp_hopoptslen);
-		ipp->ipp_hopoptslen = 0;
-	}
+	ip6_pkt_free(&sctp->sctp_sticky_ipp);
 
 	if (sctp->sctp_hopopts != NULL) {
 		mi_free(sctp->sctp_hopopts);
@@ -1062,7 +1059,8 @@
 	in6_addr_t dst;
 	sctp_faddr_t *fp;
 
-	dprint(1, ("sctp_icmp_error: sctp=%p, mp=%p\n", sctp, mp));
+	dprint(1, ("sctp_icmp_error: sctp=%p, mp=%p\n", (void *)sctp,
+	    (void *)mp));
 
 	first_mp = mp;
 
@@ -1302,6 +1300,9 @@
 
 	if ((sctp_connp = ipcl_conn_create(IPCL_SCTPCONN, sleep)) == NULL)
 		return (NULL);
+
+	sctp_connp->conn_ulp_labeled = is_system_labeled();
+
 	psctp = (sctp_t *)parent;
 
 	sctp = CONN2SCTP(sctp_connp);
@@ -1378,6 +1379,13 @@
 	sctp_connp->conn_cred = credp;
 	crhold(credp);
 
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		sctp_connp->conn_mac_exempt = B_TRUE;
+
 	/* Initialize SCTP instance values,  our verf tag must never be 0 */
 	(void) random_get_pseudo_bytes((uint8_t *)&sctp->sctp_lvtag,
 	    sizeof (sctp->sctp_lvtag));
--- a/usr/src/uts/common/inet/sctp/sctp_addr.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_addr.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -175,6 +174,7 @@
 	int		j;
 	sctp_ipif_t	*sctp_ipif;
 
+	ASSERT(zoneid != ALL_ZONES);
 	rw_enter(&sctp_g_ipifs_lock, RW_READER);
 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
 		if (sctp_g_ipifs[i].ipif_count == 0)
@@ -182,7 +182,8 @@
 		sctp_ipif = list_head(&sctp_g_ipifs[i].sctp_ipif_list);
 		for (j = 0; j < sctp_g_ipifs[i].ipif_count; j++) {
 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
-			if (zoneid == sctp_ipif->sctp_ipif_zoneid &&
+			if ((zoneid == sctp_ipif->sctp_ipif_zoneid ||
+			    sctp_ipif->sctp_ipif_zoneid == ALL_ZONES) &&
 			    SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) &&
 			    (ifindex == 0 || ifindex ==
 			    sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
@@ -225,7 +226,8 @@
 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
-			    sctp_ipif->sctp_ipif_zoneid != sctp->sctp_zoneid ||
+			    (sctp_ipif->sctp_ipif_zoneid != ALL_ZONES &&
+			    sctp_ipif->sctp_ipif_zoneid != sctp->sctp_zoneid) ||
 			    (sctp->sctp_ipversion == IPV4_VERSION &&
 			    sctp_ipif->sctp_ipif_isv6) ||
 			    (sctp->sctp_connp->conn_ipv6_v6only &&
--- a/usr/src/uts/common/inet/sctp/sctp_asconf.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_asconf.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1138,28 +1137,23 @@
 	uint16_t	type;
 	mblk_t		*mp;
 	sctp_faddr_t	*nfp;
-	sctp_parm_hdr_t	*oph;
+	sctp_parm_hdr_t	*oph = ph;
+	int		err;
 
 	*cont = 1;
 
 	/* Send back an authorization error if addip is disabled */
 	if (!sctp_addip_enabled) {
-		mp = sctp_asconf_adderr(SCTP_ERR_UNAUTHORIZED, ph, cid);
-		if (mp == NULL)
-			*cont = -1;
-		return (mp);
+		err = SCTP_ERR_UNAUTHORIZED;
+		goto error_handler;
 	}
 	/* Check input */
 	if (ntohs(ph->sph_len) < (sizeof (*ph) * 2)) {
-		mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, ph, cid);
-		if (mp == NULL) {
-			*cont = -1;
-		}
-		return (mp);
+		err = SCTP_ERR_BAD_MANDPARM;
+		goto error_handler;
 	}
 
 	type = ntohs(ph->sph_type);
-	oph = ph;
 	ph = (sctp_parm_hdr_t *)((char *)ph + sizeof (sctp_parm_hdr_t) +
 	    sizeof (cid));
 	mp = sctp_check_addip_addr(ph, oph, cont, cid, &addr);
@@ -1172,12 +1166,8 @@
 			/* Address is already part of association */
 			dprint(1, ("addip: addr already here: %x:%x:%x:%x\n",
 			    SCTP_PRINTADDR(addr)));
-			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
-			    cid);
-			if (mp == NULL) {
-				*cont = -1;
-			}
-			return (mp);
+			err = SCTP_ERR_BAD_MANDPARM;
+			goto error_handler;
 		}
 
 		if (!act) {
@@ -1185,13 +1175,17 @@
 		}
 		/* Add the new address */
 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
-		if (sctp_add_faddr(sctp, &addr, KM_NOSLEEP) != 0) {
-			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
+		err = sctp_add_faddr(sctp, &addr, KM_NOSLEEP);
+		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
+		if (err == ENOMEM) {
 			/* no memory */
 			*cont = -1;
 			return (NULL);
 		}
-		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
+		if (err != 0) {
+			err = SCTP_ERR_BAD_MANDPARM;
+			goto error_handler;
+		}
 		sctp_intf_event(sctp, addr, SCTP_ADDR_ADDED, 0);
 	} else if (type == PARM_DEL_IP) {
 		nfp = sctp_lookup_faddr(sctp, &addr);
@@ -1202,34 +1196,22 @@
 			 */
 			dprint(1, ("delip: addr not here: %x:%x:%x:%x\n",
 			    SCTP_PRINTADDR(addr)));
-			mp = sctp_asconf_adderr(SCTP_ERR_BAD_MANDPARM, oph,
-			    cid);
-			if (mp == NULL) {
-				*cont = -1;
-			}
-			return (mp);
+			err = SCTP_ERR_BAD_MANDPARM;
+			goto error_handler;
 		}
 		if (sctp->sctp_faddrs == nfp && nfp->next == NULL) {
 			/* Peer is trying to delete last address */
 			dprint(1, ("delip: del last addr: %x:%x:%x:%x\n",
 			    SCTP_PRINTADDR(addr)));
-			mp = sctp_asconf_adderr(SCTP_ERR_DEL_LAST_ADDR, oph,
-			    cid);
-			if (mp == NULL) {
-				*cont = -1;
-			}
-			return (mp);
+			err = SCTP_ERR_DEL_LAST_ADDR;
+			goto error_handler;
 		}
 		if (nfp == fp) {
 			/* Peer is trying to delete source address */
 			dprint(1, ("delip: del src addr: %x:%x:%x:%x\n",
 			    SCTP_PRINTADDR(addr)));
-			mp = sctp_asconf_adderr(SCTP_ERR_DEL_SRC_ADDR, oph,
-			    cid);
-			if (mp == NULL) {
-				*cont = -1;
-			}
-			return (mp);
+			err = SCTP_ERR_DEL_SRC_ADDR;
+			goto error_handler;
 		}
 		if (!act) {
 			return (NULL);
@@ -1267,6 +1249,12 @@
 
 	/* Successful, don't need to return anything. */
 	return (NULL);
+
+error_handler:
+	mp = sctp_asconf_adderr(err, oph, cid);
+	if (mp == NULL)
+		*cont = -1;
+	return (mp);
 }
 
 /*
--- a/usr/src/uts/common/inet/sctp/sctp_asconf.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_asconf.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,8 +39,8 @@
 	if ((fp)->rc_timer_mp != NULL) {				\
 		((sctpt_t *)((fp)->rc_timer_mp->b_rptr))->sctpt_faddr = fp;  \
 		dprint(3, ("faddr_rc_timer_restart: fp=%p %x:%x:%x:%x %d\n", \
-			    (fp), SCTP_PRINTADDR((fp)->faddr),		\
-			    (int)(intvl)));				\
+		    (void *)(fp), SCTP_PRINTADDR((fp)->faddr),		\
+		    (int)(intvl)));					\
 		sctp_timer((sctp), (fp)->rc_timer_mp, (intvl));		\
 		(fp)->rc_timer_running = 1;				\
 	}
--- a/usr/src/uts/common/inet/sctp/sctp_bind.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_bind.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,8 @@
 #include <sys/socket.h>
 #include <sys/random.h>
 #include <sys/policy.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -66,7 +67,10 @@
 	 * the same port.
 	 */
 	if (*requested_port == 0) {
-		*requested_port = sctp_update_next_port(sctp_next_port_to_try);
+		*requested_port = sctp_update_next_port(sctp_next_port_to_try,
+		    crgetzone(sctp->sctp_credp));
+		if (*requested_port == 0)
+			return (EACCES);
 		*user_specified = 0;
 	} else {
 		int i;
@@ -101,7 +105,7 @@
 				dprint(1,
 				    ("sctp_bind(x): no prive for port %d",
 				    *requested_port));
-				return (TACCES);
+				return (EACCES);
 			}
 		}
 		*user_specified = 1;
@@ -201,28 +205,21 @@
 	}
 	bind_to_req_port_only = requested_port == 0 ? B_FALSE : B_TRUE;
 
-	if (sctp_select_port(sctp, &requested_port, &user_specified) != 0) {
-		err = EPERM;
+	err = sctp_select_port(sctp, &requested_port, &user_specified);
+	if (err != 0)
 		goto done;
-	}
 
 	if ((err = sctp_bind_add(sctp, sa, 1, B_TRUE,
 	    user_specified == 1 ? htons(requested_port) : 0)) != 0) {
 		goto done;
 	}
-	allocated_port = sctp_bindi(sctp, requested_port,
-	    bind_to_req_port_only, user_specified);
-	if (allocated_port == 0) {
+	err = sctp_bindi(sctp, requested_port, bind_to_req_port_only,
+	    user_specified, &allocated_port);
+	if (err != 0) {
 		sctp_free_saddrs(sctp);
-		if (bind_to_req_port_only) {
-			err = EADDRINUSE;
-			goto done;
-		} else {
-			err = EADDRNOTAVAIL;
-			goto done;
-		}
+	} else {
+		ASSERT(sctp->sctp_state == SCTPS_BOUND);
 	}
-	ASSERT(sctp->sctp_state == SCTPS_BOUND);
 done:
 	WAKE_SCTP(sctp);
 	return (err);
@@ -438,26 +435,30 @@
 }
 
 /*
- * If the "bind_to_req_port_only" parameter is set, if the requested port
- * number is available, return it, If not return 0
+ * Returns 0 for success, errno value otherwise.
+ *
+ * If the "bind_to_req_port_only" parameter is set and the requested port
+ * number is available, then set allocated_port to it.  If not available,
+ * return an error.
  *
- * If "bind_to_req_port_only" parameter is not set and
- * If the requested port number is available, return it.  If not, return
- * the first anonymous port we happen across.  If no anonymous ports are
- * available, return 0. addr is the requested local address, if any.
+ * If the "bind_to_req_port_only" parameter is not set and the requested port
+ * number is available, then set allocated_port to it.  If not available,
+ * find the first anonymous port we can and set allocated_port to that.  If no
+ * anonymous ports are available, return an error.
  *
- * In either case, when succeeding update the sctp_t to record the port number
+ * In either case, when succeeding, update the sctp_t to record the port number
  * and insert it in the bind hash table.
  */
-in_port_t
-sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only,
-    int user_specified)
+int
+sctp_bindi(sctp_t *sctp, in_port_t port, boolean_t bind_to_req_port_only,
+    int user_specified, in_port_t *allocated_port)
 {
 	/* number of times we have run around the loop */
 	int count = 0;
 	/* maximum number of times to run around the loop */
 	int loopmax;
 	zoneid_t zoneid = sctp->sctp_zoneid;
+	zone_t *zone = crgetzone(sctp->sctp_credp);
 
 	/*
 	 * Lookup for free addresses is done in a loop and "loopmax"
@@ -507,10 +508,19 @@
 		    lsctp = lsctp->sctp_bind_hash) {
 
 			if (lport != lsctp->sctp_lport ||
-			    lsctp->sctp_zoneid != zoneid ||
 			    lsctp->sctp_state < SCTPS_BOUND)
 				continue;
 
+			/*
+			 * On a labeled system, we must treat bindings to ports
+			 * on shared IP addresses by sockets with MAC exemption
+			 * privilege as being in all zones, as there's
+			 * otherwise no way to identify the right receiver.
+			 */
+			if (lsctp->sctp_zoneid != zoneid &&
+			    !lsctp->sctp_mac_exempt && !sctp->sctp_mac_exempt)
+				continue;
+
 			addrcmp = sctp_compare_saddrs(sctp, lsctp);
 			if (addrcmp != SCTP_ADDR_DISJOINT) {
 				if (!sctp->sctp_reuseaddr) {
@@ -535,6 +545,61 @@
 			/* The port number is busy */
 			mutex_exit(&tbf->tf_lock);
 		} else {
+			conn_t *connp = sctp->sctp_connp;
+
+			if (is_system_labeled()) {
+				mlp_type_t addrtype, mlptype;
+
+				/*
+				 * On a labeled system we must check the type
+				 * of the binding requested by the user (either
+				 * MLP or SLP on shared and private addresses),
+				 * and that the user's requested binding
+				 * is permitted.
+				 */
+				addrtype = tsol_mlp_addr_type(zone->zone_id,
+				    sctp->sctp_ipversion,
+				    sctp->sctp_ipversion == IPV4_VERSION ?
+				    (void *)&sctp->sctp_ipha->ipha_src :
+				    (void *)&sctp->sctp_ip6h->ip6_src);
+
+				/*
+				 * tsol_mlp_addr_type returns the possibilities
+				 * for the selected address.  Since all local
+				 * addresses are either private or shared, the
+				 * return value mlptSingle means "local address
+				 * not valid (interface not present)."
+				 */
+				if (addrtype == mlptSingle) {
+					mutex_exit(&tbf->tf_lock);
+					return (EADDRNOTAVAIL);
+				}
+				mlptype = tsol_mlp_port_type(zone, IPPROTO_SCTP,
+				    port, addrtype);
+				if (mlptype != mlptSingle) {
+					if (secpolicy_net_bindmlp(connp->
+					    conn_cred) != 0) {
+						mutex_exit(&tbf->tf_lock);
+						return (EACCES);
+					}
+					/*
+					 * If we're binding a shared MLP, then
+					 * make sure that this zone is the one
+					 * that owns that MLP.  Shared MLPs can
+					 * be owned by at most one zone.
+					 */
+
+					if (mlptype == mlptShared &&
+					    addrtype == mlptShared &&
+					    connp->conn_zoneid !=
+					    tsol_mlp_findzone(IPPROTO_SCTP,
+					    lport)) {
+						mutex_exit(&tbf->tf_lock);
+						return (EACCES);
+					}
+					connp->conn_mlp_type = mlptype;
+				}
+			}
 			/*
 			 * This port is ours. Insert in fanout and mark as
 			 * bound to prevent others from getting the port
@@ -542,7 +607,7 @@
 			 */
 			sctp->sctp_state = SCTPS_BOUND;
 			sctp->sctp_lport = lport;
-			sctp->sctp_sctph->sh_sport = sctp->sctp_lport;
+			sctp->sctp_sctph->sh_sport = lport;
 
 			ASSERT(&sctp_bind_fanout[SCTP_BIND_HASH(port)] == tbf);
 			sctp_bind_hash_insert(tbf, sctp, 1);
@@ -552,17 +617,17 @@
 			/*
 			 * We don't want sctp_next_port_to_try to "inherit"
 			 * a port number supplied by the user in a bind.
-			 */
-			if (user_specified != 0)
-				return (port);
-
-			/*
+			 *
 			 * This is the only place where sctp_next_port_to_try
 			 * is updated. After the update, it may or may not
 			 * be in the valid range.
 			 */
-			sctp_next_port_to_try = port + 1;
-			return (port);
+			if (user_specified == 0)
+				sctp_next_port_to_try = port + 1;
+
+			*allocated_port = port;
+
+			return (0);
 		}
 
 		if ((count == 0) && (user_specified)) {
@@ -570,18 +635,22 @@
 			 * We may have to return an anonymous port. So
 			 * get one to start with.
 			 */
-			port = sctp_update_next_port(sctp_next_port_to_try);
+			port = sctp_update_next_port(sctp_next_port_to_try,
+			    zone);
 			user_specified = 0;
 		} else {
-			port = sctp_update_next_port(port + 1);
+			port = sctp_update_next_port(port + 1, zone);
 		}
+		if (port == 0)
+			break;
 
 		/*
 		 * Don't let this loop run forever in the case where
 		 * all of the anonymous ports are in use.
 		 */
 	} while (++count < loopmax);
-	return (0);
+
+	return (bind_to_req_port_only ? EADDRINUSE : EADDRNOTAVAIL);
 }
 
 /*
@@ -597,14 +666,22 @@
  * - the atomic assignment of the elements of the array
  */
 in_port_t
-sctp_update_next_port(in_port_t port)
+sctp_update_next_port(in_port_t port, zone_t *zone)
 {
 	int i;
+	boolean_t restart = B_FALSE;
 
 retry:
-	if (port < sctp_smallest_anon_port || port > sctp_largest_anon_port)
+	if (port < sctp_smallest_anon_port)
 		port = sctp_smallest_anon_port;
 
+	if (port > sctp_largest_anon_port) {
+		if (restart)
+			return (0);
+		restart = B_TRUE;
+		port = sctp_smallest_anon_port;
+	}
+
 	if (port < sctp_smallest_nonpriv_port)
 		port = sctp_smallest_nonpriv_port;
 
@@ -622,5 +699,12 @@
 			goto retry;
 		}
 	}
+
+	if (is_system_labeled() &&
+	    (i = tsol_next_port(zone, port, IPPROTO_SCTP, B_TRUE)) != 0) {
+		port = i;
+		goto retry;
+	}
+
 	return (port);
 }
--- a/usr/src/uts/common/inet/sctp/sctp_common.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_common.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,11 +28,14 @@
 #include <sys/types.h>
 #include <sys/systm.h>
 #include <sys/stream.h>
+#include <sys/strsubr.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/kmem.h>
 #include <sys/socket.h>
 #include <sys/random.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -43,12 +45,12 @@
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_ire.h>
-#include <inet/mi.h>
 #include <inet/mib2.h>
 #include <inet/nd.h>
 #include <inet/optcom.h>
 #include <inet/sctp_ip.h>
 #include <inet/ipclassifier.h>
+
 #include "sctp_impl.h"
 #include "sctp_addr.h"
 
@@ -86,6 +88,7 @@
 	sctp_saddr_ipif_t *sp;
 	uint_t	ipif_seqid;
 	int hdrlen;
+	ts_label_t *tsl;
 
 	/* Remove the previous cache IRE */
 	if ((ire = fp->ire) != NULL) {
@@ -102,76 +105,63 @@
 		fp->state = SCTP_FADDRS_UNCONFIRMED;
 	}
 
+	tsl = crgetlabel(CONN_CRED(sctp->sctp_connp));
+
 	if (fp->isv4) {
 		IN6_V4MAPPED_TO_IPADDR(&fp->faddr, addr4);
+		ire = ire_cache_lookup(addr4, sctp->sctp_zoneid, tsl);
+		if (ire != NULL)
+			IN6_IPADDR_TO_V4MAPPED(ire->ire_src_addr, &laddr);
+	} else {
+		ire = ire_cache_lookup_v6(&fp->faddr, sctp->sctp_zoneid, tsl);
+		if (ire != NULL)
+			laddr = ire->ire_src_addr_v6;
+	}
 
-		ire = ire_cache_lookup(addr4, sctp->sctp_zoneid);
-		if (ire == NULL) {
-			dprint(3, ("ire2faddr: no ire for %x:%x:%x:%x\n",
-			    SCTP_PRINTADDR(fp->faddr)));
-			/*
-			 * It is tempting to just leave the src addr
-			 * unspecified and let IP figure it out, but we
-			 * *cannot* do this, since IP may choose a src addr
-			 * that is not part of this association... unless
-			 * this sctp has bound to all addrs.  So if the ire
-			 * lookup fails, try to find one in our src addr
-			 * list, unless the sctp has bound to all addrs, in
-			 * which case we change the src addr to unspec.
-			 *
-			 * Note that if this is a v6 endpoint but it does
-			 * not have any v4 address at this point (e.g. may
-			 * have been  deleted), sctp_get_valid_addr() will
-			 * return mapped INADDR_ANY.  In this case, this
-			 * address should be marked not reachable so that
-			 * it won't be used to send data.
-			 */
-			set_saddr(sctp, fp, B_FALSE);
-			goto set_current;
-		}
-		ipif_seqid = ire->ire_ipif->ipif_seqid;
-		dprint(2, ("ire2faddr: got ire for %x:%x:%x:%x, ",
-			SCTP_PRINTADDR(fp->faddr)));
+	if (ire == NULL) {
+		dprint(3, ("ire2faddr: no ire for %x:%x:%x:%x\n",
+		    SCTP_PRINTADDR(fp->faddr)));
+		/*
+		 * It is tempting to just leave the src addr
+		 * unspecified and let IP figure it out, but we
+		 * *cannot* do this, since IP may choose a src addr
+		 * that is not part of this association... unless
+		 * this sctp has bound to all addrs.  So if the ire
+		 * lookup fails, try to find one in our src addr
+		 * list, unless the sctp has bound to all addrs, in
+		 * which case we change the src addr to unspec.
+		 *
+		 * Note that if this is a v6 endpoint but it does
+		 * not have any v4 address at this point (e.g. may
+		 * have been  deleted), sctp_get_valid_addr() will
+		 * return mapped INADDR_ANY.  In this case, this
+		 * address should be marked not reachable so that
+		 * it won't be used to send data.
+		 */
+		set_saddr(sctp, fp, B_FALSE);
+		goto set_current;
+	}
+
+	ipif_seqid = ire->ire_ipif->ipif_seqid;
+	dprint(2, ("ire2faddr: got ire for %x:%x:%x:%x, ",
+	    SCTP_PRINTADDR(fp->faddr)));
+	if (fp->isv4) {
 		dprint(2, ("src = %x\n", ire->ire_src_addr));
-		IN6_IPADDR_TO_V4MAPPED(ire->ire_src_addr, &laddr);
-
-		/* make sure the laddr is part of this association */
-		if ((sp = sctp_ipif_lookup(sctp, ipif_seqid)) !=
-		    NULL && !sp->saddr_ipif_dontsrc) {
-			if (sp->saddr_ipif_unconfirmed == 1)
-				sp->saddr_ipif_unconfirmed = 0;
-			fp->saddr = laddr;
-		} else {
-			ip2dbg(("ire2faddr: src addr is not part of assc\n"));
-			set_saddr(sctp, fp, B_FALSE);
-		}
 	} else {
-		ire = ire_cache_lookup_v6(&fp->faddr, sctp->sctp_zoneid);
-		if (ire == NULL) {
-			dprint(3, ("ire2faddr: no ire for %x:%x:%x:%x\n",
-			    SCTP_PRINTADDR(fp->faddr)));
-			set_saddr(sctp, fp, B_TRUE);
-			goto set_current;
-		}
-		ipif_seqid = ire->ire_ipif->ipif_seqid;
-		dprint(2, ("ire2faddr: got ire for %x:%x:%x:%x, ",
-		    SCTP_PRINTADDR(fp->faddr)));
 		dprint(2, ("src=%x:%x:%x:%x\n",
 		    SCTP_PRINTADDR(ire->ire_src_addr_v6)));
-		laddr = ire->ire_src_addr_v6;
-
-		/* make sure the laddr is part of this association */
+	}
 
-		if ((sp = sctp_ipif_lookup(sctp, ipif_seqid)) !=
-		    NULL && !sp->saddr_ipif_dontsrc) {
-			if (sp->saddr_ipif_unconfirmed == 1)
-				sp->saddr_ipif_unconfirmed = 0;
-			fp->saddr = laddr;
-		} else {
-			dprint(2, ("ire2faddr: src addr is not part "
-				"of assc\n"));
-			set_saddr(sctp, fp, B_TRUE);
-		}
+	/* make sure the laddr is part of this association */
+	if ((sp = sctp_ipif_lookup(sctp, ipif_seqid)) != NULL &&
+	    !sp->saddr_ipif_dontsrc) {
+		if (sp->saddr_ipif_unconfirmed == 1)
+			sp->saddr_ipif_unconfirmed = 0;
+		fp->saddr = laddr;
+	} else {
+		dprint(2, ("ire2faddr: src addr is not part of assc\n"));
+		/* set the src to the first saddr and hope for the best */
+		set_saddr(sctp, fp, B_TRUE);
 	}
 
 	/* Cache the IRE */
@@ -227,7 +217,6 @@
 	}
 }
 
-/*ARGSUSED*/
 void
 sctp_faddr2ire(sctp_t *sctp, sctp_faddr_t *fp)
 {
@@ -239,7 +228,7 @@
 
 	mutex_enter(&ire->ire_lock);
 
-	/* If the cached IRE is going sway, there is no point to update it. */
+	/* If the cached IRE is going away, there is no point to update it. */
 	if (ire->ire_marks & IRE_MARK_CONDEMNED) {
 		mutex_exit(&ire->ire_lock);
 		IRE_REFRELE_NOTR(ire);
@@ -322,9 +311,10 @@
 		ipsctplen = sctp->sctp_hdr6_len;
 	}
 
-	mp = allocb(ipsctplen + sctp_wroff_xtra + trailer, BPRI_MED);
+	mp = allocb_cred(ipsctplen + sctp_wroff_xtra + trailer,
+	    CONN_CRED(sctp->sctp_connp));
 	if (mp == NULL) {
-		ip1dbg(("sctp_make_mp: error makign mp..\n"));
+		ip1dbg(("sctp_make_mp: error making mp..\n"));
 		return (NULL);
 	}
 	mp->b_rptr += sctp_wroff_xtra;
@@ -470,66 +460,114 @@
 }
 
 /*
- * Returns 0 on success, -1 on memory allocation failure. If sleep
- * is true, should never fail.
  * Caller must hold conn fanout lock.
  */
-int
-sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep)
+static int
+sctp_add_faddr_entry(sctp_t *sctp, in6_addr_t *addr, int sleep,
+    boolean_t first)
 {
 	sctp_faddr_t *faddr;
 
-	dprint(4, ("add_faddr: %x:%x:%x:%x %d\n", SCTP_PRINTADDR(*addr),
-	    sleep));
+	if (is_system_labeled()) {
+		ts_label_t *tsl;
+		tsol_tpc_t *rhtp;
+		int retv;
+
+		tsl = crgetlabel(CONN_CRED(sctp->sctp_connp));
+		ASSERT(tsl != NULL);
+
+		/* find_tpc automatically does the right thing with IPv4 */
+		rhtp = find_tpc(addr, IPV6_VERSION, B_FALSE);
+		if (rhtp == NULL)
+			return (EACCES);
 
-	if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL) {
-		return (-1);
+		retv = EACCES;
+		if (tsl->tsl_doi == rhtp->tpc_tp.tp_doi) {
+			switch (rhtp->tpc_tp.host_type) {
+			case UNLABELED:
+				/*
+				 * Can talk to unlabeled hosts if any of the
+				 * following are true:
+				 *   1. zone's label matches the remote host's
+				 *	default label,
+				 *   2. mac_exempt is on and the zone dominates
+				 *	the remote host's label, or
+				 *   3. mac_exempt is on and the socket is from
+				 *	the global zone.
+				 */
+				if (blequal(&rhtp->tpc_tp.tp_def_label,
+				    &tsl->tsl_label) ||
+				    (sctp->sctp_mac_exempt &&
+				    (sctp->sctp_zoneid == GLOBAL_ZONEID ||
+				    bldominates(&tsl->tsl_label,
+				    &rhtp->tpc_tp.tp_def_label))))
+					retv = 0;
+				break;
+			case SUN_CIPSO:
+				if (_blinrange(&tsl->tsl_label,
+				    &rhtp->tpc_tp.tp_sl_range_cipso) ||
+				    blinlset(&tsl->tsl_label,
+				    rhtp->tpc_tp.tp_sl_set_cipso))
+					retv = 0;
+				break;
+			}
+		}
+		TPC_RELE(rhtp);
+		if (retv != 0)
+			return (retv);
 	}
 
+	if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL)
+		return (ENOMEM);
+
 	sctp_init_faddr(sctp, faddr, addr);
 	ASSERT(faddr->next == NULL);
 
-	/* tack it on to the end */
-	if (sctp->sctp_lastfaddr != NULL) {
-		sctp->sctp_lastfaddr->next = faddr;
+	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 {
-		/* list is empty */
-		ASSERT(sctp->sctp_faddrs == NULL);
-		sctp->sctp_faddrs = faddr;
+		sctp->sctp_lastfaddr->next = faddr;
+		sctp->sctp_lastfaddr = faddr;
 	}
-	sctp->sctp_lastfaddr = faddr;
 	sctp->sctp_nfaddrs++;
 
 	return (0);
 }
 
 /*
+ * Add new address to end of list.
+ * Returns 0 on success, or errno on failure:
+ *	ENOMEM	- allocation failure; only for sleep==KM_NOSLEEP
+ *	EACCES	- label is incompatible with caller or connection
+ *		  (labeled [trusted] solaris only)
+ * Caller must hold conn fanout lock.
+ */
+int
+sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep)
+{
+	dprint(4, ("add_faddr: %x:%x:%x:%x %d\n", SCTP_PRINTADDR(*addr),
+	    sleep));
+
+	return (sctp_add_faddr_entry(sctp, addr, sleep, B_FALSE));
+}
+
+/*
+ * Same as sctp_add_faddr above, but put new entry at front of list.
  * Caller must hold conn fanout lock.
  */
 int
 sctp_add_faddr_first(sctp_t *sctp, in6_addr_t *addr, int sleep)
 {
-	sctp_faddr_t *faddr;
-
 	dprint(4, ("add_faddr_first: %x:%x:%x:%x %d\n", SCTP_PRINTADDR(*addr),
 	    sleep));
 
-	if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL) {
-		return (-1);
-	}
-	sctp_init_faddr(sctp, faddr, addr);
-	ASSERT(faddr->next == NULL);
-
-	/* Put it at the beginning of the list */
-	if (sctp->sctp_faddrs != NULL) {
-		faddr->next = sctp->sctp_faddrs;
-	} else {
-		sctp->sctp_lastfaddr = faddr;
-	}
-	sctp->sctp_faddrs = faddr;
-	sctp->sctp_nfaddrs++;
-
-	return (0);
+	return (sctp_add_faddr_entry(sctp, addr, sleep, B_TRUE));
 }
 
 sctp_faddr_t *
@@ -914,6 +952,7 @@
 	ip6_pkt_t	*ipp = &sctp->sctp_sticky_ipp;
 	in6_addr_t	src;
 	in6_addr_t	dst;
+
 	/*
 	 * save the existing sctp header and source/dest IP addresses
 	 */
@@ -1028,11 +1067,60 @@
 	return (0);
 }
 
+static int
+sctp_v4_label(sctp_t *sctp)
+{
+	uchar_t optbuf[IP_MAX_OPT_LENGTH];
+	const cred_t *cr = CONN_CRED(sctp->sctp_connp);
+	int added;
+
+	if (tsol_compute_label(cr, sctp->sctp_ipha->ipha_dst, optbuf,
+	    sctp->sctp_mac_exempt) != 0)
+		return (EACCES);
+
+	added = tsol_remove_secopt(sctp->sctp_ipha, sctp->sctp_hdr_len);
+	if (added == -1)
+		return (EACCES);
+	sctp->sctp_hdr_len += added;
+	sctp->sctp_sctph = (sctp_hdr_t *)((uchar_t *)sctp->sctp_sctph + added);
+	sctp->sctp_ip_hdr_len += added;
+	if ((sctp->sctp_v4label_len = optbuf[IPOPT_OLEN]) != 0) {
+		sctp->sctp_v4label_len = (sctp->sctp_v4label_len + 3) & ~3;
+		added = tsol_prepend_option(optbuf, sctp->sctp_ipha,
+		    sctp->sctp_hdr_len);
+		if (added == -1)
+			return (EACCES);
+		sctp->sctp_hdr_len += added;
+		sctp->sctp_sctph = (sctp_hdr_t *)((uchar_t *)sctp->sctp_sctph +
+		    added);
+		sctp->sctp_ip_hdr_len += added;
+	}
+	return (0);
+}
+
+static int
+sctp_v6_label(sctp_t *sctp)
+{
+	uchar_t optbuf[TSOL_MAX_IPV6_OPTION];
+	const cred_t *cr = CONN_CRED(sctp->sctp_connp);
+
+	if (tsol_compute_label_v6(cr, &sctp->sctp_ip6h->ip6_dst, optbuf,
+	    sctp->sctp_mac_exempt) != 0)
+		return (EACCES);
+	if (tsol_update_sticky(&sctp->sctp_sticky_ipp, &sctp->sctp_v6label_len,
+	    optbuf) != 0)
+		return (EACCES);
+	if (sctp_build_hdrs(sctp) != 0)
+		return (EACCES);
+	return (0);
+}
+
 /*
  * XXX implement more sophisticated logic
  */
-void
-sctp_set_hdraddrs(sctp_t *sctp)
+/* ARGSUSED */
+int
+sctp_set_hdraddrs(sctp_t *sctp, cred_t *cr)
 {
 	sctp_faddr_t *fp;
 	int gotv4 = 0;
@@ -1048,15 +1136,18 @@
 		/* saddr may be unspec; make_mp() will handle this */
 		IN6_V4MAPPED_TO_IPADDR(&sctp->sctp_primary->saddr,
 		    sctp->sctp_ipha->ipha_src);
-		gotv4 = 1;
-		if (sctp->sctp_ipversion == IPV4_VERSION) {
-			goto copyports;
+		if (!is_system_labeled() || sctp_v4_label(sctp) == 0) {
+			gotv4 = 1;
+			if (sctp->sctp_ipversion == IPV4_VERSION) {
+				goto copyports;
+			}
 		}
 	} else {
 		sctp->sctp_ip6h->ip6_dst = sctp->sctp_primary->faddr;
 		/* saddr may be unspec; make_mp() will handle this */
 		sctp->sctp_ip6h->ip6_src = sctp->sctp_primary->saddr;
-		gotv6 = 1;
+		if (!is_system_labeled() || sctp_v6_label(sctp) == 0)
+			gotv6 = 1;
 	}
 
 	for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
@@ -1066,28 +1157,36 @@
 			/* copy in the faddr_t's saddr */
 			IN6_V4MAPPED_TO_IPADDR(&fp->saddr,
 			    sctp->sctp_ipha->ipha_src);
-			gotv4 = 1;
-			if (sctp->sctp_ipversion == IPV4_VERSION || gotv6) {
-				break;
+			if (!is_system_labeled() || sctp_v4_label(sctp) == 0) {
+				gotv4 = 1;
+				if (sctp->sctp_ipversion == IPV4_VERSION ||
+				    gotv6) {
+					break;
+				}
 			}
 		} else if (!gotv6) {
 			sctp->sctp_ip6h->ip6_dst = fp->faddr;
 			/* copy in the faddr_t's saddr */
 			sctp->sctp_ip6h->ip6_src = fp->saddr;
-			gotv6 = 1;
-			if (gotv4) {
-				break;
+			if (!is_system_labeled() || sctp_v6_label(sctp) == 0) {
+				gotv6 = 1;
+				if (gotv4)
+					break;
 			}
 		}
 	}
 
 copyports:
+	if (!gotv4 && !gotv6)
+		return (EACCES);
+
 	/* copy in the ports for good measure */
 	sctp->sctp_sctph->sh_sport = sctp->sctp_lport;
 	sctp->sctp_sctph->sh_dport = sctp->sctp_fport;
 
 	sctp->sctp_sctph6->sh_sport = sctp->sctp_lport;
 	sctp->sctp_sctph6->sh_dport = sctp->sctp_fport;
+	return (0);
 }
 
 void
@@ -1251,8 +1350,9 @@
 	fp = sctp_lookup_faddr(sctp, hdrsaddr);
 	if (fp == NULL) {
 		/* not included; add it now */
-		if (sctp_add_faddr_first(sctp, hdrsaddr, KM_NOSLEEP) == -1)
-			return (ENOMEM);
+		err = sctp_add_faddr_first(sctp, hdrsaddr, KM_NOSLEEP);
+		if (err != 0)
+			return (err);
 
 		/* sctp_faddrs will be the hdr addr */
 		fp = sctp->sctp_faddrs;
@@ -1351,10 +1451,9 @@
 					goto next;
 
 				/* OK, add it to the faddr set */
-				if (sctp_add_faddr(sctp, &addr,
-					KM_NOSLEEP) != 0) {
-					return (ENOMEM);
-				}
+				err = sctp_add_faddr(sctp, &addr, KM_NOSLEEP);
+				if (err != 0)
+					return (err);
 			}
 		} else if (ph->sph_type == htons(PARM_ADDR6) &&
 		    sctp->sctp_family == AF_INET6) {
@@ -1378,10 +1477,10 @@
 				if (sctp_lookup_faddr(sctp, addr6) != NULL)
 					goto next;
 
-				if (sctp_add_faddr(sctp,
-				    (in6_addr_t *)(ph + 1), KM_NOSLEEP) != 0) {
-					return (ENOMEM);
-				}
+				err = sctp_add_faddr(sctp,
+				    (in6_addr_t *)(ph + 1), KM_NOSLEEP);
+				if (err != 0)
+					return (err);
 			}
 		} else if (ph->sph_type == htons(PARM_FORWARD_TSN)) {
 			if (sctp_options != NULL)
@@ -1570,7 +1669,7 @@
 		if (compres == SCTP_ADDR_OVERLAP) {
 			dprint(1,
 			    ("new assoc from %x:%x:%x:%x overlaps with %p\n",
-			    SCTP_PRINTADDR(*hdraddr), sctp));
+			    SCTP_PRINTADDR(*hdraddr), (void *)sctp));
 			/*
 			 * While we still hold the lock, we need to
 			 * figure out which addresses have been
@@ -1669,77 +1768,6 @@
 	}
 }
 
-/*
- * Return zero if the buffers are identical in length and content.
- * This is used for comparing extension header buffers.
- * Note that an extension header would be declared different
- * even if all that changed was the next header value in that header i.e.
- * what really changed is the next extension header.
- */
-boolean_t
-sctp_cmpbuf(void *a, uint_t alen, boolean_t b_valid, void *b, uint_t blen)
-{
-	if (!b_valid)
-		blen = 0;
-
-	if (alen != blen)
-		return (B_TRUE);
-	if (alen == 0)
-		return (B_FALSE);	/* Both zero length */
-	return (bcmp(a, b, alen));
-}
-
-/*
- * Preallocate memory for sctp_savebuf(). Returns B_TRUE if ok.
- * Return B_FALSE if memory allocation fails - don't change any state!
- */
-boolean_t
-sctp_allocbuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
-    void *src, uint_t srclen)
-{
-	void *dst;
-
-	if (!src_valid)
-		srclen = 0;
-
-	ASSERT(*dstlenp == 0);
-	if (src != NULL && srclen != 0) {
-		dst = mi_zalloc(srclen);
-		if (dst == NULL)
-			return (B_FALSE);
-	} else {
-		dst = NULL;
-	}
-	if (*dstp != NULL) {
-		mi_free(*dstp);
-		*dstp = NULL;
-		*dstlenp = 0;
-	}
-	*dstp = dst;
-	if (dst != NULL)
-		*dstlenp = srclen;
-	else
-		*dstlenp = 0;
-	return (B_TRUE);
-}
-
-/*
- * Replace what is in *dst, *dstlen with the source.
- * Assumes sctp_allocbuf has already been called.
- */
-void
-sctp_savebuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
-    void *src, uint_t srclen)
-{
-	if (!src_valid)
-		srclen = 0;
-
-	ASSERT(*dstlenp == srclen);
-	if (src != NULL && srclen != 0) {
-		bcopy(src, *dstp, srclen);
-	}
-}
-
 static void
 sctp_init_faddr(sctp_t *sctp, sctp_faddr_t *fp, in6_addr_t *addr)
 {
@@ -1799,7 +1827,7 @@
 }
 
 void
-sctp_faddr_init()
+sctp_faddr_init(void)
 {
 	sctp_kmem_faddr_cache = kmem_cache_create("sctp_faddr_cache",
 	    sizeof (sctp_faddr_t), 0, NULL, faddr_destructor,
@@ -1807,7 +1835,7 @@
 }
 
 void
-sctp_faddr_fini()
+sctp_faddr_fini(void)
 {
 	kmem_cache_destroy(sctp_kmem_faddr_cache);
 }
--- a/usr/src/uts/common/inet/sctp/sctp_conn.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_conn.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,6 +35,7 @@
 #include <sys/stropts.h>
 #include <sys/strsubr.h>
 #include <sys/socket.h>
+#include <sys/tsol/tndb.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -63,6 +63,8 @@
 	sctp_init_chunk_t	*init;
 	int			err;
 	uint_t			sctp_options;
+	conn_t			*lconnp;
+	cred_t			*cr;
 
 	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
 	ASSERT(OK_32PTR(sctph));
@@ -80,6 +82,20 @@
 	if (err != 0)
 		return (err);
 
+	lconnp = listener->sctp_connp;
+	if (lconnp->conn_mlp_type != mlptSingle) {
+		cr = lconnp->conn_peercred = DB_CRED(cr_pkt);
+		if (cr != NULL)
+			crhold(cr);
+		else
+			cr = lconnp->conn_cred;
+	} else {
+		cr = lconnp->conn_cred;
+	}
+
+	if ((err = sctp_set_hdraddrs(acceptor, cr)) != 0)
+		return (err);
+
 	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
 	    listener->sctp_prsctp_aware && sctp_prsctp_enabled) {
 		acceptor->sctp_prsctp_aware = B_TRUE;
@@ -89,8 +105,6 @@
 	/* The new sctp_t is fully bound now. */
 	acceptor->sctp_connp->conn_fully_bound = B_TRUE;
 
-	sctp_set_hdraddrs(acceptor);
-
 	/* Get  initial TSNs */
 	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
 	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
@@ -298,7 +312,6 @@
  * bind and conn fanouts, sends the INIT, and replies to the client
  * with an OK ack.
  */
-/* ARGSUSED */
 int
 sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen)
 {
@@ -313,6 +326,7 @@
 	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
 	int 		hdrlen;
 	ip6_rthdr_t	*rth;
+	int		err;
 	sctp_faddr_t	*cur_fp;
 
 	/*
@@ -406,7 +420,6 @@
 
 	switch (sctp->sctp_state) {
 	case SCTPS_IDLE: {
-		int			err;
 		struct sockaddr_storage	ss;
 
 		/*
@@ -464,10 +477,10 @@
 		 * OK; set up the peer addr (this may grow after we get
 		 * the INIT ACK from the peer with additional addresses).
 		 */
-		if (sctp_add_faddr(sctp, &dstaddr, sleep) < 0) {
+		if ((err = sctp_add_faddr(sctp, &dstaddr, sleep)) != 0) {
 			mutex_exit(&tbf->tf_lock);
 			WAKE_SCTP(sctp);
-			return (ENOMEM);
+			return (err);
 		}
 		/* No valid src addr, return. */
 		if (sctp->sctp_faddrs->state == SCTP_FADDRS_UNREACH) {
@@ -483,7 +496,11 @@
 		mutex_exit(&tbf->tf_lock);
 
 		/* initialize composite headers */
-		sctp_set_hdraddrs(sctp);
+		if ((err = sctp_set_hdraddrs(sctp, NULL)) != 0) {
+			sctp_conn_hash_remove(sctp);
+			WAKE_SCTP(sctp);
+			return (err);
+		}
 
 		/*
 		 * Massage a routing header (if present) putting the first hop
--- a/usr/src/uts/common/inet/sctp/sctp_cookie.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,6 +33,7 @@
 #include <sys/kmem.h>
 #include <sys/strsubr.h>
 #include <sys/random.h>
+#include <sys/tsol/tnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -441,6 +441,7 @@
 	mblk_t			*errmp = NULL;
 	boolean_t		initcollision = B_FALSE;
 	boolean_t		linklocal = B_FALSE;
+	cred_t			*cr;
 
 	BUMP_LOCAL(sctp->sctp_ibchunks);
 	isv4 = (IPH_HDR_VERSION(initmp->b_rptr) == IPV4_VERSION);
@@ -533,7 +534,8 @@
 		pad = 4 - pad;
 		ipsctplen += pad;
 	}
-	iackmp = allocb(ipsctplen + sctp_wroff_xtra, BPRI_MED);
+	iackmp = allocb_cred(ipsctplen + sctp_wroff_xtra,
+	    CONN_CRED(sctp->sctp_connp));
 	if (iackmp == NULL) {
 		sctp_send_abort(sctp, sctp_init2vtag(ch),
 		    SCTP_ERR_NO_RESOURCES, NULL, 0, initmp, 0, B_FALSE);
@@ -693,6 +695,30 @@
 	iackmp->b_wptr = iackmp->b_rptr + ipsctplen;
 	iackmp->b_cont = errmp;		/*  OK if NULL */
 
+	if (is_system_labeled() && (cr = DB_CRED(initmp)) != NULL &&
+	    crgetlabel(cr) != NULL) {
+		conn_t *connp = sctp->sctp_connp;
+		int err, adjust;
+
+		if (isv4)
+			err = tsol_check_label(cr, &iackmp, &adjust,
+			    connp->conn_mac_exempt);
+		else
+			err = tsol_check_label_v6(cr, &iackmp, &adjust,
+			    connp->conn_mac_exempt);
+		if (err != 0) {
+			sctp_send_abort(sctp, sctp_init2vtag(ch),
+			    SCTP_ERR_AUTH_ERR, NULL, 0, initmp, 0, B_FALSE);
+			freemsg(iackmp);
+			return;
+		}
+		if (isv4) {
+			iackiph = (ipha_t *)iackmp->b_rptr;
+			adjust += ntohs(iackiph->ipha_length);
+			iackiph->ipha_length = htons(adjust);
+		}
+	}
+
 	/*
 	 * Stash the conn ptr info. for IP only as e don't have any
 	 * cached IRE.
@@ -1303,7 +1329,7 @@
 
 			dprint(1,
 			    ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n",
-			    SCTP_PRINTADDR(src), sctp));
+			    SCTP_PRINTADDR(src), (void *)sctp));
 
 
 			if (sctp != NULL) {
@@ -1316,7 +1342,7 @@
 
 			dprint(1,
 			    ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n",
-			    SCTP_PRINTADDR(src), sctp));
+			    SCTP_PRINTADDR(src), (void *)sctp));
 
 			if (sctp != NULL) {
 				return (sctp);
--- a/usr/src/uts/common/inet/sctp/sctp_error.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_error.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +31,7 @@
 #include <sys/cmn_err.h>
 #include <sys/ddi.h>
 #include <sys/strsubr.h>
+#include <sys/tsol/tnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -161,6 +161,9 @@
 	int		isv4;
 	ire_t		*ire;
 	irb_t		*irb;
+	ts_label_t	*tsl;
+	conn_t		*connp;
+	cred_t		*cr;
 
 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
 	if (isv4) {
@@ -169,7 +172,14 @@
 		ahlen = sctp->sctp_hdr6_len;
 	}
 
-	hmp = allocb(sctp_wroff_xtra + ahlen, BPRI_MED);
+	/*
+	 * If this is a labeled system, then check to see if we're allowed to
+	 * send a response to this particular sender.  If not, then just drop.
+	 */
+	if (is_system_labeled() && !tsol_can_reply_error(inmp))
+		return;
+
+	hmp = allocb_cred(sctp_wroff_xtra + ahlen, CONN_CRED(sctp->sctp_connp));
 	if (hmp == NULL) {
 		/* XXX no resources */
 		return;
@@ -233,24 +243,48 @@
 		ahip6h->ip6_plen = htons(alen + sizeof (*sh));
 	}
 
-	/* Stash the conn ptr info. for IP */
-	SCTP_STASH_IPINFO(hmp, (ire_t *)NULL);
-
 	BUMP_MIB(&sctp_mib, sctpAborted);
 	BUMP_LOCAL(sctp->sctp_obchunks);
 
-	CONN_INC_REF(sctp->sctp_connp);
+	connp = sctp->sctp_connp;
+	if (is_system_labeled() && (cr = DB_CRED(inmp)) != NULL &&
+	    crgetlabel(cr) != NULL) {
+		int err, adjust;
+
+		if (isv4)
+			err = tsol_check_label(cr, &hmp, &adjust,
+			    connp->conn_mac_exempt);
+		else
+			err = tsol_check_label_v6(cr, &hmp, &adjust,
+			    connp->conn_mac_exempt);
+		if (err != 0) {
+			freemsg(hmp);
+			return;
+		}
+		if (isv4) {
+			ahiph = (ipha_t *)hmp->b_rptr;
+			adjust += ntohs(ahiph->ipha_length);
+			ahiph->ipha_length = htons(adjust);
+		}
+	}
+
+	/* Stash the conn ptr info. for IP */
+	SCTP_STASH_IPINFO(hmp, NULL);
+
+	CONN_INC_REF(connp);
 	hmp->b_flag |= MSGHASREF;
-	IP_PUT(hmp, sctp->sctp_connp, sctp->sctp_current == NULL ? B_TRUE :
+	IP_PUT(hmp, connp, sctp->sctp_current == NULL ? B_TRUE :
 	    sctp->sctp_current->isv4);
 	/*
 	 * Let's just mark the IRE for this destination as temporary
 	 * to prevent any DoS attack.
 	 */
+	tsl = cr == NULL ? NULL : crgetlabel(cr);
 	if (isv4)
-		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid);
+		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid, tsl);
 	else
-		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid);
+		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid,
+		    tsl);
 	/*
 	 * In the normal case the ire would be non-null, however it could be
 	 * null, say, if IP needs to resolve the gateway for this address. We
--- a/usr/src/uts/common/inet/sctp/sctp_hash.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_hash.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,7 +29,8 @@
 #include <sys/socket.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
-#include <sys/strsun.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip6.h>
@@ -339,6 +339,7 @@
 	return (sctp);
 }
 
+/* called by ipsec_sctp_pol */
 conn_t *
 sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
     uint_t ipif_seqid, zoneid_t zoneid)
@@ -356,6 +357,37 @@
 	return (sctp->sctp_connp);
 }
 
+conn_t *
+sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
+    uint_t ipif_seqid, zoneid_t zoneid, mblk_t *mp)
+{
+	sctp_t *sctp;
+
+	if ((sctp = sctp_conn_match(src, dst, ports, ipif_seqid,
+	    zoneid)) == NULL) {
+		if (zoneid == ALL_ZONES) {
+			zoneid = tsol_mlp_findzone(IPPROTO_SCTP,
+			    htons(ntohl(ports) & 0xFFFF));
+			/*
+			 * If no shared MLP is found, tsol_mlp_findzone returns
+			 * ALL_ZONES.  In that case, we assume it's SLP, and
+			 * search for the zone based on the packet label.
+			 * That will also return ALL_ZONES on failure.
+			 */
+			if (zoneid == ALL_ZONES)
+				zoneid = tsol_packet_to_zoneid(mp);
+			if (zoneid == ALL_ZONES)
+				return (NULL);
+		}
+		/* Not in conn fanout; check listen fanout */
+		if ((sctp = listen_match(dst, ports, ipif_seqid,
+		    zoneid)) == NULL) {
+			return (NULL);
+		}
+	}
+	return (sctp->sctp_connp);
+}
+
 /*
  * Fanout for SCTP packets
  * The caller puts <fport, lport> in the ports parameter.
@@ -400,7 +432,7 @@
 		dst = &map_dst;
 		isv4 = B_TRUE;
 	}
-	if ((connp = sctp_find_conn(src, dst, ports, ipif_seqid, zoneid)) ==
+	if ((connp = sctp_fanout(src, dst, ports, ipif_seqid, zoneid, mp)) ==
 	    NULL) {
 		ip_fanout_sctp_raw(mp, recv_ill, ipha, isv4,
 		    ports, mctl_present, flags, ip_policy,
--- a/usr/src/uts/common/inet/sctp/sctp_heartbeat.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_heartbeat.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -67,7 +66,7 @@
 	ASSERT(fp != NULL);
 
 	dprint(3, ("sctp_return_heartbeat: %p got hb from %x:%x:%x:%x\n",
-	    sctp, SCTP_PRINTADDR(addr)));
+	    (void *)sctp, SCTP_PRINTADDR(addr)));
 
 	/*
 	 * XXX It's really tempting to reuse the heartbeat mblk. But
@@ -276,7 +275,7 @@
 	    sizeof (sent) + sizeof (secret) + sizeof (addr))) {
 		/* drop it */
 		dprint(2, ("sctp_process_heartbeat: malformed ack %p\n",
-		    sctp));
+		    (void *)sctp));
 		return;
 	}
 
@@ -285,7 +284,7 @@
 	    ntohs(hpp->sph_len) != (ntohs(cp->sch_len) - sizeof (*cp))) {
 		dprint(2,
 		    ("sctp_process_heartbeat: malformed param in ack %p\n",
-		    sctp));
+		    (void *)sctp));
 		return;
 	}
 
@@ -305,13 +304,13 @@
 	fp = sctp_lookup_faddr(sctp, &addr);
 	if (fp == NULL) {
 		dprint(2, ("sctp_process_heartbeat: invalid faddr (sctp=%p)\n",
-		    sctp));
+		    (void *)sctp));
 		return;
 	}
 	if (secret != fp->hb_secret) {
 		dprint(2,
 		    ("sctp_process_heartbeat: invalid secret in ack %p\n",
-		    sctp));
+		    (void *)sctp));
 		return;
 	}
 
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,7 @@
 #include <sys/taskq.h>
 #include <sys/list.h>
 #include <sys/strsun.h>
+#include <sys/zone.h>
 #include <netinet/ip6.h>
 #include <inet/optcom.h>
 #include <netinet/sctp.h>
@@ -73,8 +73,8 @@
 	if ((fp)->timer_mp != NULL) {					\
 		((sctpt_t *)((fp)->timer_mp->b_rptr))->sctpt_faddr = fp;  \
 		dprint(3, ("faddr_timer_restart: fp=%p %x:%x:%x:%x %d\n", \
-			    (fp), SCTP_PRINTADDR((fp)->faddr),		\
-			    (int)(intvl)));				\
+		    (void *)(fp), SCTP_PRINTADDR((fp)->faddr),		\
+		    (int)(intvl)));					\
 		sctp_timer((sctp), (fp)->timer_mp, (intvl));		\
 		(fp)->timer_running = 1;				\
 	}
@@ -428,16 +428,12 @@
 
 /* debugging */
 #undef	dprint
-#if defined(DEBUG) && !defined(lint)
+#ifdef DEBUG
 extern int sctpdebug;
-
 #define	dprint(level, args)	{ if (sctpdebug > (level)) printf args; }
-
-#else /* define(DEBUG) && !defined(lint) */
-
+#else
 #define	dprint(level, args) {}
-
-#endif /* defined(DEBUG) && !defined(lint) */
+#endif
 
 
 /* Peer address tracking */
@@ -746,7 +742,9 @@
 		sctp_chk_fast_rexmit : 1, /* check for fast rexmit message */
 
 		sctp_prsctp_aware : 1,	/* is peer PR-SCTP aware? */
-		sctp_linklocal : 1;	/* is linklocal assoc. */
+		sctp_linklocal : 1,	/* is linklocal assoc. */
+		sctp_mac_exempt : 1,	/* SO_MAC_EXEMPT */
+		sctp_dummy : 5;
 	} sctp_bits;
 	struct {
 		uint32_t
@@ -788,6 +786,7 @@
 #define	sctp_chk_fast_rexmit sctp_bits.sctp_chk_fast_rexmit
 #define	sctp_prsctp_aware sctp_bits.sctp_prsctp_aware
 #define	sctp_linklocal sctp_bits.sctp_linklocal
+#define	sctp_mac_exempt sctp_bits.sctp_mac_exempt
 
 #define	sctp_recvsndrcvinfo sctp_events.sctp_recvsndrcvinfo
 #define	sctp_recvassocevnt sctp_events.sctp_recvassocevnt
@@ -901,6 +900,9 @@
 	/* Stats */
 	uint64_t	sctp_msgcount;
 	uint64_t	sctp_prsctpdrop;
+
+	uint_t		sctp_v4label_len;	/* length of cached v4 label */
+	uint_t		sctp_v6label_len;	/* length of cached v6 label */
 } sctp_t;
 
 extern list_t	sctp_g_list;	/* Head of SCTP instance data chain */
@@ -933,13 +935,12 @@
 		    uint_t, zoneid_t);
 extern void	sctp_add_hdr(sctp_t *, uchar_t *, size_t);
 extern void	sctp_check_adv_ack_pt(sctp_t *, mblk_t *, mblk_t *);
-extern boolean_t sctp_allocbuf(void **, uint_t *, boolean_t, void *, uint_t);
 extern void	sctp_assoc_event(sctp_t *, uint16_t, uint16_t,
 		    sctp_chunk_hdr_t *);
 
 extern void	sctp_bind_hash_insert(sctp_tf_t *, sctp_t *, int);
 extern void	sctp_bind_hash_remove(sctp_t *);
-extern in_port_t sctp_bindi(sctp_t *, in_port_t, int, int);
+extern int	sctp_bindi(sctp_t *, in_port_t, boolean_t, int, in_port_t *);
 extern int	sctp_bind_add(sctp_t *, const void *, uint32_t, boolean_t,
 		    in_port_t);
 extern int	sctp_bind_del(sctp_t *, const void *, uint32_t, boolean_t);
@@ -949,7 +950,6 @@
 extern void	sctp_chunkify(sctp_t *, int, int);
 extern void	sctp_clean_death(sctp_t *, int);
 extern void	sctp_close_eager(sctp_t *);
-extern boolean_t sctp_cmpbuf(void *, uint_t, boolean_t, void *, uint_t);
 extern int	sctp_compare_faddrsets(sctp_faddr_t *, sctp_faddr_t *);
 extern void	sctp_congest_reset(sctp_t *);
 extern void	sctp_conn_hash_insert(sctp_tf_t *, sctp_t *, int);
@@ -966,14 +966,14 @@
 extern void	sctp_dispatch_rput(queue_t *, sctp_t *, sctp_hdr_t *, mblk_t *,
 		    uint_t, uint_t, in6_addr_t);
 extern char	*sctp_display(sctp_t *, char *);
-extern void	sctp_display_all();
+extern void	sctp_display_all(void);
 
 extern void	sctp_error_event(sctp_t *, sctp_chunk_hdr_t *);
 
 extern void	sctp_faddr_alive(sctp_t *, sctp_faddr_t *);
 extern int	sctp_faddr_dead(sctp_t *, sctp_faddr_t *, int);
-extern void	sctp_faddr_fini();
-extern void	sctp_faddr_init();
+extern void	sctp_faddr_fini(void);
+extern void	sctp_faddr_init(void);
 extern void	sctp_faddr2hdraddr(sctp_faddr_t *, sctp_t *);
 extern void	sctp_faddr2ire(sctp_t *, sctp_faddr_t *);
 extern void	sctp_fast_rexmit(sctp_t *);
@@ -994,7 +994,6 @@
 extern mblk_t	*sctp_get_first_sent(sctp_t *);
 extern mblk_t	*sctp_get_msg_to_send(sctp_t *, mblk_t **, mblk_t *, int  *,
 		    int32_t, uint32_t, sctp_faddr_t *);
-extern in_port_t sctp_get_next_priv_port();
 extern void	sctp_get_saddr_list(sctp_t *, uchar_t *, size_t);
 
 extern int	sctp_handle_error(sctp_t *, sctp_hdr_t *, sctp_chunk_hdr_t *,
@@ -1039,9 +1038,9 @@
 extern void	sctp_maxpsz_set(sctp_t *);
 extern void	sctp_move_faddr_timers(queue_t *, sctp_t *);
 
-extern void	sctp_nd_free();
+extern void	sctp_nd_free(void);
 extern int	sctp_nd_getset(queue_t *, MBLKP);
-extern boolean_t sctp_nd_init();
+extern boolean_t sctp_nd_init(void);
 extern sctp_parm_hdr_t *sctp_next_parm(sctp_parm_hdr_t *, ssize_t *);
 
 extern void	sctp_ootb_shutdown_ack(sctp_t *, mblk_t *, uint_t);
@@ -1065,7 +1064,6 @@
 extern sctp_faddr_t *sctp_rotate_faddr(sctp_t *, sctp_faddr_t *);
 
 extern void	sctp_sack(sctp_t *, mblk_t *);
-extern void	sctp_savebuf(void **, uint_t *, boolean_t, void *, uint_t);
 extern int	sctp_secure_restart_check(mblk_t *, sctp_chunk_hdr_t *,
 		    uint32_t, int);
 extern void	sctp_send_abort(sctp_t *, uint32_t, uint16_t, char *, size_t,
@@ -1077,9 +1075,9 @@
 extern void	sctp_send_shutdown(sctp_t *, int);
 extern void	sctp_send_heartbeat(sctp_t *, sctp_faddr_t *);
 extern void	sctp_sendfail_event(sctp_t *, mblk_t *, int, boolean_t);
-extern void	sctp_set_hdraddrs(sctp_t *);
-extern void	sctp_sets_init();
-extern void	sctp_sets_fini();
+extern int	sctp_set_hdraddrs(sctp_t *, cred_t *);
+extern void	sctp_sets_init(void);
+extern void	sctp_sets_fini(void);
 extern void	sctp_shutdown_event(sctp_t *);
 extern void	sctp_stop_faddr_timers(sctp_t *);
 extern int	sctp_shutdown_received(sctp_t *, sctp_chunk_hdr_t *, int, int);
@@ -1097,7 +1095,7 @@
 extern void	sctp_timer_stop(mblk_t *);
 extern void	sctp_unlink_faddr(sctp_t *, sctp_faddr_t *);
 
-extern in_port_t sctp_update_next_port(in_port_t);
+extern in_port_t sctp_update_next_port(in_port_t, zone_t *zone);
 extern void	sctp_update_rtt(sctp_t *, sctp_faddr_t *, clock_t);
 extern void	sctp_user_abort(sctp_t *, mblk_t *, boolean_t);
 
--- a/usr/src/uts/common/inet/sctp/sctp_input.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_input.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -382,14 +381,15 @@
 	}
 	/* If app asked for hopbyhop headers and it has changed ... */
 	if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVHOPOPTS) &&
-	    sctp_cmpbuf(sctp->sctp_hopopts, sctp->sctp_hopoptslen,
+	    ip_cmpbuf(sctp->sctp_hopopts, sctp->sctp_hopoptslen,
 		(ipp->ipp_fields & IPPF_HOPOPTS),
 		ipp->ipp_hopopts, ipp->ipp_hopoptslen)) {
-		optlen += sizeof (*cmsg) + ipp->ipp_hopoptslen;
+		optlen += sizeof (*cmsg) + ipp->ipp_hopoptslen -
+		    sctp->sctp_v6label_len;
 		if (hdrlen == 0)
 			hdrlen = sizeof (struct T_unitdata_ind);
 		addflag |= SCTP_IPV6_RECVHOPOPTS;
-		if (!sctp_allocbuf((void **)&sctp->sctp_hopopts,
+		if (!ip_allocbuf((void **)&sctp->sctp_hopopts,
 		    &sctp->sctp_hopoptslen,
 		    (ipp->ipp_fields & IPPF_HOPOPTS),
 		    ipp->ipp_hopopts, ipp->ipp_hopoptslen))
@@ -397,14 +397,14 @@
 	}
 	/* If app asked for dst headers before routing headers ... */
 	if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVRTDSTOPTS) &&
-	    sctp_cmpbuf(sctp->sctp_rtdstopts, sctp->sctp_rtdstoptslen,
+	    ip_cmpbuf(sctp->sctp_rtdstopts, sctp->sctp_rtdstoptslen,
 		(ipp->ipp_fields & IPPF_RTDSTOPTS),
 		ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen)) {
 		optlen += sizeof (*cmsg) + ipp->ipp_rtdstoptslen;
 		if (hdrlen == 0)
 			hdrlen = sizeof (struct T_unitdata_ind);
 		addflag |= SCTP_IPV6_RECVRTDSTOPTS;
-		if (!sctp_allocbuf((void **)&sctp->sctp_rtdstopts,
+		if (!ip_allocbuf((void **)&sctp->sctp_rtdstopts,
 		    &sctp->sctp_rtdstoptslen,
 		    (ipp->ipp_fields & IPPF_RTDSTOPTS),
 		    ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen))
@@ -412,14 +412,14 @@
 	}
 	/* If app asked for routing headers and it has changed ... */
 	if (sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVRTHDR) {
-		if (sctp_cmpbuf(sctp->sctp_rthdr, sctp->sctp_rthdrlen,
+		if (ip_cmpbuf(sctp->sctp_rthdr, sctp->sctp_rthdrlen,
 		    (ipp->ipp_fields & IPPF_RTHDR),
 		    ipp->ipp_rthdr, ipp->ipp_rthdrlen)) {
 			optlen += sizeof (*cmsg) + ipp->ipp_rthdrlen;
 			if (hdrlen == 0)
 				hdrlen = sizeof (struct T_unitdata_ind);
 			addflag |= SCTP_IPV6_RECVRTHDR;
-			if (!sctp_allocbuf((void **)&sctp->sctp_rthdr,
+			if (!ip_allocbuf((void **)&sctp->sctp_rthdr,
 			    &sctp->sctp_rthdrlen,
 			    (ipp->ipp_fields & IPPF_RTHDR),
 			    ipp->ipp_rthdr, ipp->ipp_rthdrlen))
@@ -428,14 +428,14 @@
 	}
 	/* If app asked for dest headers and it has changed ... */
 	if ((sctp->sctp_ipv6_recvancillary & SCTP_IPV6_RECVDSTOPTS) &&
-	    sctp_cmpbuf(sctp->sctp_dstopts, sctp->sctp_dstoptslen,
+	    ip_cmpbuf(sctp->sctp_dstopts, sctp->sctp_dstoptslen,
 		(ipp->ipp_fields & IPPF_DSTOPTS),
 		ipp->ipp_dstopts, ipp->ipp_dstoptslen)) {
 		optlen += sizeof (*cmsg) + ipp->ipp_dstoptslen;
 		if (hdrlen == 0)
 			hdrlen = sizeof (struct T_unitdata_ind);
 		addflag |= SCTP_IPV6_RECVDSTOPTS;
-		if (!sctp_allocbuf((void **)&sctp->sctp_dstopts,
+		if (!ip_allocbuf((void **)&sctp->sctp_dstopts,
 		    &sctp->sctp_dstoptslen,
 		    (ipp->ipp_fields & IPPF_DSTOPTS),
 		    ipp->ipp_dstopts, ipp->ipp_dstoptslen))
@@ -546,7 +546,7 @@
 		optptr += ipp->ipp_hopoptslen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		sctp_savebuf((void **)&sctp->sctp_hopopts,
+		ip_savebuf((void **)&sctp->sctp_hopopts,
 		    &sctp->sctp_hopoptslen,
 		    (ipp->ipp_fields & IPPF_HOPOPTS),
 		    ipp->ipp_hopopts, ipp->ipp_hopoptslen);
@@ -562,7 +562,7 @@
 		optptr += ipp->ipp_rtdstoptslen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		sctp_savebuf((void **)&sctp->sctp_rtdstopts,
+		ip_savebuf((void **)&sctp->sctp_rtdstopts,
 		    &sctp->sctp_rtdstoptslen,
 		    (ipp->ipp_fields & IPPF_RTDSTOPTS),
 		    ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen);
@@ -578,7 +578,7 @@
 		optptr += ipp->ipp_rthdrlen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		sctp_savebuf((void **)&sctp->sctp_rthdr,
+		ip_savebuf((void **)&sctp->sctp_rthdr,
 		    &sctp->sctp_rthdrlen,
 		    (ipp->ipp_fields & IPPF_RTHDR),
 		    ipp->ipp_rthdr, ipp->ipp_rthdrlen);
@@ -594,7 +594,7 @@
 		optptr += ipp->ipp_dstoptslen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		sctp_savebuf((void **)&sctp->sctp_dstopts,
+		ip_savebuf((void **)&sctp->sctp_dstopts,
 		    &sctp->sctp_dstoptslen,
 		    (ipp->ipp_fields & IPPF_DSTOPTS),
 		    ipp->ipp_dstopts, ipp->ipp_dstoptslen);
@@ -1207,7 +1207,7 @@
 	dc = (sctp_data_hdr_t *)ch;
 	tsn = ntohl(dc->sdh_tsn);
 
-	dprint(3, ("sctp_data_chunk: mp=%p tsn=%x\n", mp, tsn));
+	dprint(3, ("sctp_data_chunk: mp=%p tsn=%x\n", (void *)mp, tsn));
 
 	/* Check for duplicates */
 	if (SEQ_LT(tsn, sctp->sctp_ftsn)) {
@@ -1628,7 +1628,7 @@
 		if (sctp->sctp_sack_toggle < 2) {
 			/* no need to SACK right now */
 			dprint(2, ("sctp_make_sack: %p no sack (toggle)\n",
-			    sctp));
+			    (void *)sctp));
 			return (NULL);
 		} else if (sctp->sctp_sack_toggle >= 2) {
 			sctp->sctp_sack_toggle = 0;
@@ -1636,7 +1636,8 @@
 	}
 
 	if (sctp->sctp_ftsn == sctp->sctp_lastacked + 1) {
-		dprint(2, ("sctp_make_sack: %p no sack (already)\n", sctp));
+		dprint(2, ("sctp_make_sack: %p no sack (already)\n",
+		    (void *)sctp));
 		return (NULL);
 	}
 
@@ -1686,7 +1687,8 @@
 	sctp_set_iplen(sctp, smp);
 
 	dprint(2, ("sctp_sack: sending to %p %x:%x:%x:%x\n",
-	    sctp->sctp_lastdata, SCTP_PRINTADDR(sctp->sctp_lastdata->faddr)));
+	    (void *)sctp->sctp_lastdata,
+	    SCTP_PRINTADDR(sctp->sctp_lastdata->faddr)));
 
 	sctp->sctp_active = lbolt64;
 
@@ -3453,7 +3455,8 @@
 
 	/* Have a valid sctp for this packet */
 	fp = sctp_lookup_faddr(sctp, &src);
-	dprint(2, ("sctp_dispatch_rput: mp=%p fp=%p sctp=%p\n", mp, fp, sctp));
+	dprint(2, ("sctp_dispatch_rput: mp=%p fp=%p sctp=%p\n", (void *)mp,
+	    (void *)fp, (void *)sctp));
 
 	gotdata = 0;
 	trysend = 0;
@@ -3688,6 +3691,8 @@
 				BUMP_MIB(&sctp_mib, sctpPassiveEstab);
 				if (mlen > ntohs(ch->sch_len)) {
 					eager->sctp_cookie_mp = dupb(mp);
+					mblk_setcred(eager->sctp_cookie_mp,
+					    CONN_CRED(eager->sctp_connp));
 					/*
 					 * If no mem, just let
 					 * the peer retransmit.
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,171 +62,57 @@
 static int	sctp_getpeeraddrs(sctp_t *, void *, int *);
 
 /*
- * Set optbuf and optlen for the option.
- * Allocate memory (if not already present).
- * Otherwise just point optbuf and optlen at invalp and inlen.
- * Returns failure if memory can not be allocated.
- */
-static int
-sctp_pkt_set(uchar_t *invalp, uint_t inlen, uchar_t **optbufp, uint_t *optlenp)
-{
-	uchar_t *optbuf;
-
-	if (inlen == *optlenp) {
-		/* Unchanged length - no need to realocate */
-		bcopy(invalp, *optbufp, inlen);
-		return (0);
-	}
-	if (inlen != 0) {
-		/* Allocate new buffer before free */
-		optbuf = kmem_zalloc(inlen, KM_NOSLEEP);
-		if (optbuf == NULL)
-			return (ENOMEM);
-	} else {
-		optbuf = NULL;
-	}
-	/* Free old buffer */
-	if (*optlenp != 0)
-		kmem_free(*optbufp, *optlenp);
-
-	bcopy(invalp, optbuf, inlen);
-	*optbufp = optbuf;
-	*optlenp = inlen;
-	return (0);
-}
-
-/*
- * Use the outgoing IP header to create an IP_OPTIONS option the way
- * it was passed down from the application.
- */
-static int
-sctp_opt_get_user(ipha_t *ipha, uchar_t *buf)
-{
-	uchar_t		*opt;
-	int		totallen;
-	uint32_t	optval;
-	uint32_t	optlen;
-	uint32_t	len = 0;
-	uchar_t	*buf1 = buf;
-
-	buf += IP_ADDR_LEN;	/* Leave room for final destination */
-	len += IP_ADDR_LEN;
-	bzero(buf1, IP_ADDR_LEN);
-
-	totallen = ipha->ipha_version_and_hdr_length -
-		(uint8_t)((IP_VERSION << 4) + IP_SIMPLE_HDR_LENGTH_IN_WORDS);
-	opt = (uchar_t *)&ipha[1];
-	totallen <<= 2;
-	while (totallen != 0) {
-		switch (optval = opt[IPOPT_OPTVAL]) {
-		case IPOPT_EOL:
-			goto done;
-		case IPOPT_NOP:
-			optlen = 1;
-			break;
-		default:
-			optlen = opt[IPOPT_OLEN];
-		}
-		if (optlen == 0 || optlen > totallen)
-			break;
-
-		switch (optval) {
-			int	off;
-		case IPOPT_SSRR:
-		case IPOPT_LSRR:
-
-			/*
-			 * Insert ipha_dst as the first entry in the source
-			 * route and move down the entries on step.
-			 * The last entry gets placed at buf1.
-			 */
-			buf[IPOPT_OPTVAL] = optval;
-			buf[IPOPT_OLEN] = optlen;
-			buf[IPOPT_OFFSET] = optlen;
-
-			off = optlen - IP_ADDR_LEN;
-			if (off < 0) {
-				/* No entries in source route */
-				break;
-			}
-			/* Last entry in source route */
-			bcopy(opt + off, buf1, IP_ADDR_LEN);
-			off -= IP_ADDR_LEN;
-
-			while (off > 0) {
-				bcopy(opt + off,
-				    buf + off + IP_ADDR_LEN,
-				    IP_ADDR_LEN);
-				off -= IP_ADDR_LEN;
-			}
-			/* ipha_dst into first slot */
-			bcopy(&ipha->ipha_dst,
-			    buf + off + IP_ADDR_LEN,
-			    IP_ADDR_LEN);
-			buf += optlen;
-			len += optlen;
-			break;
-		default:
-			bcopy(opt, buf, optlen);
-			buf += optlen;
-			len += optlen;
-			break;
-		}
-		totallen -= optlen;
-		opt += optlen;
-	}
-done:
-	/* Pad the resulting options */
-	while (len & 0x3) {
-		*buf++ = IPOPT_EOL;
-		len++;
-	}
-	return (len);
-}
-
-
-/*
  * Copy the standard header into its new location,
  * lay in the new options and then update the relevant
  * fields in both sctp_t and the standard header.
- * NOTE: this could be simpler if we trusted bcopy()
- * with overlapping src/dst.
+ * Returns 0 on success, errno otherwise.
  */
 static int
-sctp_opt_set_header(sctp_t *sctp, boolean_t checkonly, const void *ptr,
-    uint_t len)
+sctp_opt_set_header(sctp_t *sctp, const void *ptr, uint_t len)
 {
-	char	buf[SCTP_MAX_HDR_LENGTH];
-	uint_t	sctph_len;
-
-	if (checkonly) {
-		/*
-		 * do not really set, just pretend to - T_CHECK
-		 */
-		if (len != 0) {
-			/*
-			 * there is value supplied, validate it as if
-			 * for a real set operation.
-			 */
-			if ((len > SCTP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
-				return (EINVAL);
-		}
-		return (0);
-	}
+	uint8_t *ip_optp;
+	sctp_hdr_t *new_sctph;
 
 	if ((len > SCTP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
 		return (EINVAL);
-	sctph_len = sizeof (sctp_hdr_t);
-	bcopy(sctp->sctp_sctph, buf, sctph_len);
-	bcopy(ptr, (char *)sctp->sctp_ipha + IP_SIMPLE_HDR_LENGTH, len);
-	len += IP_SIMPLE_HDR_LENGTH;
-	sctp->sctp_sctph = (sctp_hdr_t *)((char *)sctp->sctp_ipha + len);
-	bcopy(buf, sctp->sctp_sctph, sctph_len);
+
+	if (len > IP_MAX_OPT_LENGTH - sctp->sctp_v4label_len)
+		return (EINVAL);
+
+	ip_optp = (uint8_t *)sctp->sctp_ipha + IP_SIMPLE_HDR_LENGTH;
+
+	if (sctp->sctp_v4label_len > 0) {
+		int padlen;
+		uint8_t opt;
+
+		/* convert list termination to no-ops as needed */
+		padlen = sctp->sctp_v4label_len - ip_optp[IPOPT_OLEN];
+		ip_optp += ip_optp[IPOPT_OLEN];
+		opt = len > 0 ? IPOPT_NOP : IPOPT_EOL;
+		while (--padlen >= 0)
+			*ip_optp++ = opt;
+		ASSERT(ip_optp == (uint8_t *)sctp->sctp_ipha +
+		    IP_SIMPLE_HDR_LENGTH + sctp->sctp_v4label_len);
+	}
+
+	/*
+	 * Move the existing SCTP header out where it belongs.
+	 */
+	new_sctph = (sctp_hdr_t *)(ip_optp + len);
+	ovbcopy(sctp->sctp_sctph, new_sctph, sizeof (sctp_hdr_t));
+	sctp->sctp_sctph = new_sctph;
+
+	/*
+	 * Insert the new user-supplied IP options.
+	 */
+	if (len > 0)
+		bcopy(ptr, ip_optp, len);
+
+	len += sctp->sctp_v4label_len;
 	sctp->sctp_ip_hdr_len = len;
 	sctp->sctp_ipha->ipha_version_and_hdr_length =
-		(IP_VERSION << 4) | (len >> 2);
-	len += sctph_len;
-	sctp->sctp_hdr_len = len;
+	    (IP_VERSION << 4) | (len >> 2);
+	sctp->sctp_hdr_len = len + sizeof (sctp_hdr_t);
 
 	if (sctp->sctp_current) {
 		/*
@@ -839,6 +724,9 @@
 		case SO_RCVBUF:
 			*i1 = sctp->sctp_rwnd;
 			break;
+		case SO_MAC_EXEMPT:
+			*i1 = sctp->sctp_mac_exempt ? SO_MAC_EXEMPT : 0;
+			break;
 		default:
 			retval = EINVAL;
 			break;
@@ -1006,7 +894,7 @@
 			 * will contain the final destination. Allocate a
 			 * buffer large enough to hold all the options, we
 			 * add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
-			 * sctp_opt_get_user() adds the final destination
+			 * ip_opt_get_user() adds the final destination
 			 * at the start.
 			 */
 			char	*opt_ptr;
@@ -1022,7 +910,7 @@
 				 * TODO: Do we have to handle getsockopt on an
 				 * initiator as well?
 				 */
-				opt_len = sctp_opt_get_user(sctp->sctp_ipha,
+				opt_len = ip_opt_get_user(sctp->sctp_ipha,
 				    obuf);
 				ASSERT(opt_len <= sizeof (obuf));
 			} else {
@@ -1148,16 +1036,35 @@
 			*optlen = sizeof (sin6_t);
 			break;
 		}
-		case IPV6_HOPOPTS:
+		case IPV6_HOPOPTS: {
+			int len;
+
 			if (!(ipp->ipp_fields & IPPF_HOPOPTS))
 				break;
-			if (buflen < ipp->ipp_hopoptslen) {
+			len = ipp->ipp_hopoptslen - sctp->sctp_v6label_len;
+			if (len <= 0)
+				break;
+			if (buflen < len) {
 				retval = EINVAL;
 				break;
 			}
-			bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen);
-			*optlen  = ipp->ipp_hopoptslen;
+			bcopy((char *)ipp->ipp_hopopts +
+			    sctp->sctp_v6label_len, ptr, len);
+			if (sctp->sctp_v6label_len > 0) {
+				char *cptr = ptr;
+
+				/*
+				 * If the label length is greater than zero,
+				 * then we need to hide the label from user.
+				 * Make it look as though a normal Hop-By-Hop
+				 * Options Header is present here.
+				 */
+				cptr[0] = ((char *)ipp->ipp_hopopts)[0];
+				cptr[1] = (len + 7) / 8 - 1;
+			}
+			*optlen = len;
 			break;
+		}
 		case IPV6_RTHDRDSTOPTS:
 			if (!(ipp->ipp_fields & IPPF_RTDSTOPTS))
 				break;
@@ -1316,6 +1223,15 @@
 			 * and sctp_opt_get ?
 			 */
 			break;
+		case SO_MAC_EXEMPT:
+			if (secpolicy_net_mac_aware(sctp->sctp_credp) != 0 ||
+			    sctp->sctp_state >= SCTPS_BOUND) {
+				retval = EACCES;
+			} else {
+				sctp->sctp_mac_exempt = onoff;
+				connp->conn_mac_exempt = onoff;
+			}
+			break;
 		default:
 			retval = EINVAL;
 			break;
@@ -1465,8 +1381,7 @@
 		switch (name) {
 		case IP_OPTIONS:
 		case T_IP_OPTIONS:
-			retval = sctp_opt_set_header(sctp, B_FALSE,
-			    invalp, inlen);
+			retval = sctp_opt_set_header(sctp, invalp, inlen);
 			break;
 		case IP_TOS:
 		case T_IP_TOS:
@@ -1700,8 +1615,9 @@
 					ire_t	*ire;
 
 					ire = ire_route_lookup_v6(
-					    &sin6->sin6_addr, 0, 0, 0, NULL,
-					    NULL, NULL, MATCH_IRE_DEFAULT);
+					    &sin6->sin6_addr, NULL, NULL, 0,
+					    NULL, NULL, ALL_ZONES, NULL,
+					    MATCH_IRE_DEFAULT);
 					if (ire == NULL) {
 						retval = EHOSTUNREACH;
 						break;
@@ -1722,16 +1638,15 @@
 				break;
 			}
 
-			if (inlen == 0) {
+			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
+			    B_TRUE, (uchar_t **)&ipp->ipp_hopopts,
+			    &ipp->ipp_hopoptslen, sctp->sctp_v6label_len);
+			if (retval != 0)
+				break;
+			if (ipp->ipp_hopoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
-			} else {
-				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
-				    (uchar_t **)&ipp->ipp_hopopts,
-				    &ipp->ipp_hopoptslen);
-				if (retval != 0)
-					break;
+			else
 				ipp->ipp_fields |= IPPF_HOPOPTS;
-			}
 			retval = sctp_build_hdrs(sctp);
 			break;
 		}
@@ -1744,16 +1659,15 @@
 				break;
 			}
 
-			if (inlen == 0) {
+			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
+			    B_TRUE, (uchar_t **)&ipp->ipp_rtdstopts,
+			    &ipp->ipp_rtdstoptslen, 0);
+			if (retval != 0)
+				break;
+			if (ipp->ipp_rtdstoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
-			} else {
-				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
-				    (uchar_t **)&ipp->ipp_rtdstopts,
-				    &ipp->ipp_rtdstoptslen);
-				if (retval != 0)
-					break;
+			else
 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
-			}
 			retval = sctp_build_hdrs(sctp);
 			break;
 		}
@@ -1766,16 +1680,15 @@
 				break;
 			}
 
-			if (inlen == 0) {
+			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
+			    B_TRUE, (uchar_t **)&ipp->ipp_dstopts,
+			    &ipp->ipp_dstoptslen, 0);
+			if (retval != 0)
+				break;
+			if (ipp->ipp_dstoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
-			} else {
-				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
-				    (uchar_t **)&ipp->ipp_dstopts,
-				    &ipp->ipp_dstoptslen);
-				if (retval != 0)
-					break;
+			else
 				ipp->ipp_fields |= IPPF_DSTOPTS;
-			}
 			retval = sctp_build_hdrs(sctp);
 			break;
 		}
@@ -1788,16 +1701,15 @@
 				break;
 			}
 
-			if (inlen == 0) {
+			retval = optcom_pkt_set((uchar_t *)invalp, inlen,
+			    B_TRUE, (uchar_t **)&ipp->ipp_rthdr,
+			    &ipp->ipp_rthdrlen, 0);
+			if (retval != 0)
+				break;
+			if (ipp->ipp_rthdrlen == 0)
 				ipp->ipp_fields &= ~IPPF_RTHDR;
-			} else {
-				retval = sctp_pkt_set((uchar_t *)invalp, inlen,
-				    (uchar_t **)&ipp->ipp_rthdr,
-				    &ipp->ipp_rthdrlen);
-				if (retval != 0)
-					break;
+			else
 				ipp->ipp_fields |= IPPF_RTHDR;
-			}
 			retval = sctp_build_hdrs(sctp);
 			break;
 		}
--- a/usr/src/uts/common/inet/sctp/sctp_output.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_output.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,17 +36,15 @@
 #include <sys/strsun.h>
 #include <sys/strsubr.h>
 #include <sys/socketvar.h>
-
-#include <netinet/in.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp_seq.h>
-#include <netinet/sctp.h>
+/* swilly code in sys/socketvar.h turns off DEBUG */
+#ifdef __lint
+#define	DEBUG
+#endif
 
 #include <inet/common.h>
 #include <inet/mi.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
-#include <inet/ip_ire.h>
 #include <inet/sctp_ip.h>
 #include <inet/ipclassifier.h>
 
@@ -589,7 +586,8 @@
 		 * data was moved into chunks, or during retransmission,
 		 * or things like snoop is running.
 		 */
-		nmp = allocb(sctp_wroff_xtra + hdrlen + sacklen, BPRI_MED);
+		nmp = allocb_cred(sctp_wroff_xtra + hdrlen + sacklen,
+		    CONN_CRED(sctp->sctp_connp));
 		if (nmp == NULL) {
 			if (error !=  NULL)
 				*error = ENOMEM;
@@ -601,6 +599,7 @@
 		mp = nmp;
 	} else {
 		mp->b_rptr -= (hdrlen + sacklen);
+		mblk_setcred(mp, CONN_CRED(sctp->sctp_connp));
 	}
 	bcopy(hdr, mp->b_rptr, hdrlen);
 	if (sacklen) {
@@ -1210,10 +1209,10 @@
 		ASSERT(cansend >= seglen - pad - xtralen);
 		cansend -= (seglen - pad - xtralen);
 		dprint(2, ("sctp_output: Sending packet %d bytes, tsn %x "
-			"ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n",
-			seglen - xtralen, ntohl(sdc->sdh_tsn),
-			ntohs(sdc->sdh_ssn), fp, sctp->sctp_frwnd, cansend,
-			sctp->sctp_lastack_rxd));
+		    "ssn %d to %p (rwnd %d, cansend %d, lastack_rxd %x)\n",
+		    seglen - xtralen, ntohl(sdc->sdh_tsn),
+		    ntohs(sdc->sdh_ssn), (void *)fp, sctp->sctp_frwnd,
+		    cansend, sctp->sctp_lastack_rxd));
 		sctp_set_iplen(sctp, head);
 		sctp_add_sendq(sctp, head);
 		/* arm rto timer (if not set) */
@@ -1348,7 +1347,7 @@
 		xtralen = sctp->sctp_hdr_len + sctp_wroff_xtra;
 	else
 		xtralen = sctp->sctp_hdr6_len + sctp_wroff_xtra;
-	ftsn_mp = allocb(xtralen + seglen, BPRI_MED);
+	ftsn_mp = allocb_cred(xtralen + seglen, CONN_CRED(sctp->sctp_connp));
 	if (ftsn_mp == NULL)
 		return (NULL);
 	ftsn_mp->b_rptr += xtralen;
@@ -1818,8 +1817,8 @@
 	}
 	dprint(2, ("sctp_rexmit: Sending packet %d bytes, tsn %x "
 	    "ssn %d to %p (rwnd %d, lastack_rxd %x)\n",
-	    seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn), fp,
-	    sctp->sctp_frwnd, sctp->sctp_lastack_rxd));
+	    seglen, ntohl(sdc->sdh_tsn), ntohs(sdc->sdh_ssn),
+	    (void *)fp, sctp->sctp_frwnd, sctp->sctp_lastack_rxd));
 
 	sctp_set_iplen(sctp, head);
 	sctp_add_sendq(sctp, head);
--- a/usr/src/uts/common/inet/sctp/sctp_snmp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,6 +32,7 @@
 #include <sys/tihdr.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
+#include <sys/tsol/tndb.h>
 
 #include <netinet/in.h>
 
@@ -306,16 +306,23 @@
 	mblk_t			*mp_rem_ctl = NULL;
 	mblk_t			*mp_rem_data;
 	mblk_t			*mp_rem_tail = NULL;
+	mblk_t			*mp_attr_ctl = NULL;
+	mblk_t			*mp_attr_data;
+	mblk_t			*mp_attr_tail = NULL;
 	struct opthdr		*optp;
 	sctp_t			*sctp, *sctp_prev = NULL;
 	sctp_faddr_t		*fp;
 	mib2_sctpConnEntry_t	sce;
 	mib2_sctpConnLocalEntry_t	scle;
 	mib2_sctpConnRemoteEntry_t	scre;
+	mib2_transportMLPEntry_t	mlp;
 	int			i;
 	int			l;
 	int			scanned = 0;
 	zoneid_t		zoneid = Q_TO_CONN(q)->conn_zoneid;
+	conn_t			*connp;
+	boolean_t		needattr;
+	int			idx;
 
 	/*
 	 * Make copies of the original message.
@@ -326,10 +333,13 @@
 	mp_conn_ctl = copymsg(mpctl);
 	mp_local_ctl = copymsg(mpctl);
 	mp_rem_ctl = copymsg(mpctl);
+	mp_attr_ctl = copymsg(mpctl);
 
 	mpdata = mpctl->b_cont;
 
-	if (!mp_conn_ctl || !mp_local_ctl || !mp_rem_ctl || !mpdata) {
+	if (mp_conn_ctl == NULL || mp_local_ctl == NULL ||
+	    mp_rem_ctl == NULL || mp_attr_ctl == NULL || mpdata == NULL) {
+		freemsg(mp_attr_ctl);
 		freemsg(mp_rem_ctl);
 		freemsg(mp_local_ctl);
 		freemsg(mp_conn_ctl);
@@ -340,6 +350,7 @@
 	mp_conn_data = mp_conn_ctl->b_cont;
 	mp_local_data = mp_local_ctl->b_cont;
 	mp_rem_data = mp_rem_ctl->b_cont;
+	mp_attr_data = mp_attr_ctl->b_cont;
 
 	/* hostname address parameters are not supported in Solaris */
 	sce.sctpAssocRemHostName.o_length = 0;
@@ -355,6 +366,7 @@
 	SET_MIB(sctp_mib.sctpMaxInitRetr, sctp_max_init_retr);
 	SET_MIB(sctp_mib.sctpCurrEstab, 0);
 
+	idx = 0;
 	sctp = gsctp;
 	mutex_enter(&sctp_g_lock);
 	while (sctp != NULL) {
@@ -492,6 +504,26 @@
 			(void) snmp_append_data2(mp_rem_data, &mp_rem_tail,
 			    (char *)&scre, sizeof (scre));
 		}
+		connp = sctp->sctp_connp;
+		needattr = B_FALSE;
+		bzero(&mlp, sizeof (mlp));
+		if (connp->conn_mlp_type != mlptSingle) {
+			if (connp->conn_mlp_type == mlptShared ||
+			    connp->conn_mlp_type == mlptBoth)
+				mlp.tme_flags |= MIB2_TMEF_SHARED;
+			if (connp->conn_mlp_type == mlptPrivate ||
+			    connp->conn_mlp_type == mlptBoth)
+				mlp.tme_flags |= MIB2_TMEF_PRIVATE;
+			needattr = B_TRUE;
+		}
+		if (connp->conn_peercred != NULL) {
+			ts_label_t *tsl;
+
+			tsl = crgetlabel(connp->conn_peercred);
+			mlp.tme_doi = label2doi(tsl);
+			mlp.tme_label = *label2bslabel(tsl);
+			needattr = B_TRUE;
+		}
 		WAKE_SCTP(sctp);
 		sce.sctpAssocState = sctp_snmp_state(sctp);
 		sce.sctpAssocInStreams = sctp->sctp_num_istr;
@@ -511,6 +543,10 @@
 		sce.sctpConnEntryInfo.ce_mss = sctp->sctp_mss;
 		(void) snmp_append_data2(mp_conn_data, &mp_conn_tail,
 		    (char *)&sce, sizeof (sce));
+		mlp.tme_connidx = idx++;
+		if (needattr)
+			(void) snmp_append_data2(mp_attr_ctl->b_cont,
+			    &mp_attr_tail, (char *)&mlp, sizeof (mlp));
 next_sctp:
 		sctp_prev = sctp;
 		mutex_enter(&sctp_g_lock);
@@ -555,6 +591,17 @@
 	optp->len = msgdsize(mp_rem_data);
 	qreply(q, mp_rem_ctl);
 
+	/* table of MLP attributes */
+	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_SCTP;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp_attr_data);
+	if (optp->len == 0)
+		freemsg(mp_attr_ctl);
+	else
+		qreply(q, mp_attr_ctl);
+
 	return (mp_ret);
 }
 
--- a/usr/src/uts/common/inet/sctp/sctp_timer.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp/sctp_timer.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -237,7 +236,7 @@
 	sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
 	state = sctp_tb->sctp_tb_state;
 
-	dprint(5, ("sctp_timer_free %p state %d\n", mp, state));
+	dprint(5, ("sctp_timer_free %p state %d\n", (void *)mp, state));
 
 	if (state == SCTP_TB_RUNNING) {
 		if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
@@ -272,7 +271,7 @@
 	sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
 	state = sctp_tb->sctp_tb_state;
 
-	dprint(5, ("sctp_timer_stop %p %d\n", mp, state));
+	dprint(5, ("sctp_timer_stop %p %d\n", (void *)mp, state));
 
 	if (state == SCTP_TB_RUNNING) {
 		if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
@@ -673,7 +672,7 @@
 	rtt = (int)delta;
 	rtt = rtt > 0 ? rtt : 1;
 
-	dprint(5, ("sctp_update_rtt: fp = %p, rtt = %d\n", fp, rtt));
+	dprint(5, ("sctp_update_rtt: fp = %p, rtt = %d\n", (void *)fp, rtt));
 
 	/* Is this the first RTT measurement? */
 	if (fp->srtt == -1) {
--- a/usr/src/uts/common/inet/sctp_ip.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/sctp_ip.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,6 +41,9 @@
 extern void sctp_ddi_destroy(void);
 extern conn_t *sctp_find_conn(in6_addr_t *, in6_addr_t *, uint32_t, uint_t,
     zoneid_t);
+extern conn_t *sctp_fanout(in6_addr_t *, in6_addr_t *, uint32_t, uint_t,
+    zoneid_t, mblk_t *);
+
 extern void sctp_input(conn_t *, ipha_t *, mblk_t *, mblk_t *, ill_t *,
     boolean_t, boolean_t);
 extern void sctp_wput(queue_t *, mblk_t *);
--- a/usr/src/uts/common/inet/tcp.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/tcp.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -551,6 +550,7 @@
 	boolean_t		tcp_kssl_inhandshake; /* during SSL handshake */
 	kssl_ent_t		tcp_kssl_ent;	/* SSL table entry */
 	kssl_ctx_t		tcp_kssl_ctx;	/* SSL session */
+	uint_t	tcp_label_len;	/* length of cached label */
 } tcp_t;
 
 extern void 	tcp_free(tcp_t *tcp);
--- a/usr/src/uts/common/inet/tcp/tcp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -54,6 +54,7 @@
 #include <sys/multidata_impl.h>
 #include <sys/pattr.h>
 #include <sys/policy.h>
+#include <sys/priv.h>
 #include <sys/zone.h>
 
 #include <sys/errno.h>
@@ -95,6 +96,10 @@
 #include <inet/ipp_common.h>
 #include <sys/squeue.h>
 #include <inet/kssl/ksslapi.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+#include <sys/sdt.h>
+#include <rpc/pmap_prot.h>
 
 /*
  * TCP Notes: aka FireEngine Phase I (PSARC 2002/433)
@@ -218,7 +223,6 @@
  * can be sent out.
  */
 
-
 extern major_t TCP6_MAJ;
 
 /*
@@ -838,7 +842,6 @@
 static boolean_t tcp_allow_connopt_set(int level, int name);
 int		tcp_opt_default(queue_t *q, int level, int name, uchar_t *ptr);
 int		tcp_opt_get(queue_t *q, int level, int name, uchar_t *ptr);
-static int	tcp_opt_get_user(ipha_t *ipha, uchar_t *ptr);
 int		tcp_opt_set(queue_t *q, uint_t optset_context, int level,
 		    int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
 		    uchar_t *outvalp, void *thisdg_attrs, cred_t *cr,
@@ -891,8 +894,9 @@
 		    cred_t *cr);
 static void	tcp_timer(void *arg);
 static void	tcp_timer_callback(void *);
-static in_port_t tcp_update_next_port(in_port_t port, boolean_t random);
-static in_port_t tcp_get_next_priv_port(void);
+static in_port_t tcp_update_next_port(in_port_t port, const tcp_t *tcp,
+    boolean_t random);
+static in_port_t tcp_get_next_priv_port(const tcp_t *);
 static void	tcp_wput_sock(queue_t *q, mblk_t *mp);
 void		tcp_wput_accept(queue_t *q, mblk_t *mp);
 static void	tcp_wput_data(tcp_t *tcp, mblk_t *mp, boolean_t urgent);
@@ -912,7 +916,6 @@
 		    int num_sack_blk);
 static void	tcp_wsrv(queue_t *q);
 static int	tcp_xmit_end(tcp_t *tcp);
-void		tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len);
 static mblk_t	*tcp_xmit_mp(tcp_t *tcp, mblk_t *mp, int32_t max_to_send,
 		    int32_t *offset, mblk_t **end_mp, uint32_t seq,
 		    boolean_t sendall, uint32_t *seg_len, boolean_t rexmit);
@@ -930,15 +933,8 @@
 		    boolean_t, boolean_t);
 static void	tcp_icmp_error_ipv6(tcp_t *tcp, mblk_t *mp,
 		    boolean_t ipsec_mctl);
-static boolean_t tcp_cmpbuf(void *a, uint_t alen,
-		    boolean_t b_valid, void *b, uint_t blen);
-static boolean_t tcp_allocbuf(void **dstp, uint_t *dstlenp,
-		    boolean_t src_valid, void *src, uint_t srclen);
-static void	tcp_savebuf(void **dstp, uint_t *dstlenp,
-		    boolean_t src_valid, void *src, uint_t srclen);
 static mblk_t	*tcp_setsockopt_mp(int level, int cmd,
 		    char *opt, int optlen);
-static int	tcp_pkt_set(uchar_t *, uint_t, uchar_t **, uint_t *);
 static int	tcp_build_hdrs(queue_t *, tcp_t *);
 static void	tcp_time_wait_processing(tcp_t *tcp, mblk_t *mp,
 		    uint32_t seg_seq, uint32_t seg_ack, int seg_len,
@@ -1107,7 +1103,7 @@
 kmutex_t tcp_epriv_port_lock;
 
 /*
- * The smallest anonymous port in the priviledged port range which TCP
+ * The smallest anonymous port in the privileged port range which TCP
  * looks for free port.  Use in the option TCP_ANONPRIVBIND.
  */
 static in_port_t tcp_min_anonpriv_port = 512;
@@ -1360,14 +1356,14 @@
 
 /*
  * This controls the rate some ndd info report functions can be used
- * by non-priviledged users.  It stores the last time such info is
+ * by non-privileged users.  It stores the last time such info is
  * requested.  When those report functions are called again, this
  * is checked with the current time and compare with the ndd param
  * tcp_ndd_get_info_interval.
  */
 static clock_t tcp_last_ndd_get_info_time = 0;
 #define	NDD_TOO_QUICK_MSG \
-	"ndd get info rate too high for non-priviledged users, try again " \
+	"ndd get info rate too high for non-privileged users, try again " \
 	"later.\n"
 #define	NDD_OUT_OF_BUF_MSG	"<< Out of buffer >>\n"
 
@@ -1724,6 +1720,10 @@
 	tcp_iphc_len = tcp->tcp_iphc_len;
 	tcp_hdr_grown = tcp->tcp_hdr_grown;
 
+	if (connp->conn_cred != NULL)
+		crfree(connp->conn_cred);
+	if (connp->conn_peercred != NULL)
+		crfree(connp->conn_peercred);
 	bzero(connp, sizeof (conn_t));
 	bzero(tcp, sizeof (tcp_t));
 
@@ -2410,10 +2410,17 @@
 	ASSERT(eager->tcp_ack_tid == 0);
 
 	econnp->conn_dev = aconnp->conn_dev;
+	if (eager->tcp_cred != NULL)
+		crfree(eager->tcp_cred);
 	eager->tcp_cred = econnp->conn_cred = aconnp->conn_cred;
 	econnp->conn_zoneid = aconnp->conn_zoneid;
 	aconnp->conn_cred = NULL;
 
+	econnp->conn_mac_exempt = aconnp->conn_mac_exempt;
+	aconnp->conn_mac_exempt = B_FALSE;
+
+	ASSERT(aconnp->conn_peercred == NULL);
+
 	/* Do the IPC initialization */
 	CONN_INC_REF(econnp);
 
@@ -2475,6 +2482,9 @@
 	conn_t		*connp = tcp->tcp_connp;
 	boolean_t	ire_cacheable = B_FALSE;
 	zoneid_t	zoneid = connp->conn_zoneid;
+	int		match_flags = MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
+			    MATCH_IRE_SECATTR;
+	ts_label_t	*tsl = crgetlabel(CONN_CRED(connp));
 	ill_t		*ill = NULL;
 	boolean_t	incoming = (ire_mp == NULL);
 
@@ -2493,16 +2503,25 @@
 		 * ire, if it exists, will be marked private.
 		 * If that is not available, use the interface ire
 		 * for the nexthop.
+		 *
+		 * TSol: tcp_update_label will detect label mismatches based
+		 * only on the destination's label, but that would not
+		 * detect label mismatches based on the security attributes
+		 * of routes or next hop gateway. Hence we need to pass the
+		 * label to ire_ftable_lookup below in order to locate the
+		 * right prefix (and/or) ire cache. Similarly we also need
+		 * pass the label to the ire_cache_lookup below to locate
+		 * the right ire that also matches on the label.
 		 */
 		if (tcp->tcp_connp->conn_nexthop_set) {
 			ire = ire_ctable_lookup(tcp->tcp_connp->conn_rem,
 			    tcp->tcp_connp->conn_nexthop_v4, 0, NULL, zoneid,
-			    MATCH_IRE_MARK_PRIVATE_ADDR | MATCH_IRE_GW);
+			    tsl, MATCH_IRE_MARK_PRIVATE_ADDR | MATCH_IRE_GW);
 			if (ire == NULL) {
 				ire = ire_ftable_lookup(
 				    tcp->tcp_connp->conn_nexthop_v4,
 				    0, 0, IRE_INTERFACE, NULL, NULL, zoneid, 0,
-				    MATCH_IRE_TYPE);
+				    tsl, match_flags);
 				if (ire == NULL)
 					return (0);
 			} else {
@@ -2510,7 +2529,7 @@
 			}
 		} else {
 			ire = ire_cache_lookup(tcp->tcp_connp->conn_rem,
-			    zoneid);
+			    zoneid, tsl);
 			if (ire != NULL) {
 				ire_cacheable = B_TRUE;
 				ire_uinfo = (ire_mp != NULL) ?
@@ -2522,7 +2541,7 @@
 					ire = ire_ftable_lookup(
 					    tcp->tcp_connp->conn_rem,
 					    0, 0, 0, NULL, &sire, zoneid, 0,
-					    (MATCH_IRE_RECURSIVE |
+					    tsl, (MATCH_IRE_RECURSIVE |
 					    MATCH_IRE_DEFAULT));
 					if (ire == NULL)
 						return (0);
@@ -2601,7 +2620,6 @@
 		 */
 		ill_t	*dst_ill = NULL;
 		ipif_t  *dst_ipif = NULL;
-		int match_flags = MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT;
 
 		ASSERT(connp->conn_outgoing_ill == connp->conn_incoming_ill);
 
@@ -2619,7 +2637,7 @@
 			dst_ipif = dst_ill->ill_ipif;
 		}
 		ire = ire_ctable_lookup_v6(&tcp->tcp_connp->conn_remv6,
-		    0, 0, dst_ipif, zoneid, match_flags);
+		    0, 0, dst_ipif, zoneid, tsl, match_flags);
 
 		if (ire != NULL) {
 			ire_cacheable = B_TRUE;
@@ -2631,7 +2649,7 @@
 				ire = ire_ftable_lookup_v6(
 				    &tcp->tcp_connp->conn_remv6,
 				    0, 0, 0, dst_ipif, &sire, zoneid,
-				    0, match_flags);
+				    0, tsl, match_flags);
 				if (ire == NULL) {
 					if (dst_ill != NULL)
 						ill_refrele(dst_ill);
@@ -2955,6 +2973,11 @@
 	uint_t	origipversion;
 	int	err;
 	queue_t *q = tcp->tcp_wq;
+	conn_t	*connp;
+	mlp_type_t addrtype, mlptype;
+	zone_t	*zone;
+	cred_t	*cr;
+	in_port_t mlp_port;
 
 	ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
 	if ((mp->b_wptr - mp->b_rptr) < sizeof (*tbr)) {
@@ -3134,14 +3157,41 @@
 	 * still check for ports only in the range > tcp_smallest_non_priv_port,
 	 * unless TCP_ANONPRIVBIND option is set.
 	 */
+	mlptype = mlptSingle;
+	mlp_port = requested_port;
 	if (requested_port == 0) {
 		requested_port = tcp->tcp_anon_priv_bind ?
-		    tcp_get_next_priv_port() :
-		    tcp_update_next_port(tcp_next_port_to_try, B_TRUE);
+		    tcp_get_next_priv_port(tcp) :
+		    tcp_update_next_port(tcp_next_port_to_try, tcp, B_TRUE);
+		if (requested_port == 0) {
+			tcp_err_ack(tcp, mp, TNOADDR, 0);
+			return;
+		}
 		user_specified = B_FALSE;
+
+		/*
+		 * If the user went through one of the RPC interfaces to create
+		 * this socket and RPC is MLP in this zone, then give him an
+		 * anonymous MLP.
+		 */
+		cr = DB_CREDDEF(mp, tcp->tcp_cred);
+		connp = tcp->tcp_connp;
+		if (connp->conn_anon_mlp && is_system_labeled()) {
+			zone = crgetzone(cr);
+			addrtype = tsol_mlp_addr_type(zone->zone_id,
+			    IPV6_VERSION, &v6addr);
+			if (addrtype == mlptSingle) {
+				tcp_err_ack(tcp, mp, TNOADDR, 0);
+				return;
+			}
+			mlptype = tsol_mlp_port_type(zone, IPPROTO_TCP,
+			    PMAPPORT, addrtype);
+			mlp_port = PMAPPORT;
+		}
 	} else {
 		int i;
 		boolean_t priv = B_FALSE;
+
 		/*
 		 * If the requested_port is in the well-known privileged range,
 		 * verify that the stream was opened by a privileged user.
@@ -3151,6 +3201,7 @@
 		 *   changes
 		 * - the atomic assignment of the elements of the array
 		 */
+		cr = DB_CREDDEF(mp, tcp->tcp_cred);
 		if (requested_port < tcp_smallest_nonpriv_port) {
 			priv = B_TRUE;
 		} else {
@@ -3163,8 +3214,6 @@
 			}
 		}
 		if (priv) {
-			cred_t *cr = DB_CREDDEF(mp, tcp->tcp_cred);
-
 			if (secpolicy_net_privaddr(cr, requested_port) != 0) {
 				if (tcp->tcp_debug) {
 					(void) strlog(TCP_MOD_ID, 0, 1,
@@ -3177,12 +3226,87 @@
 			}
 		}
 		user_specified = B_TRUE;
+
+		connp = tcp->tcp_connp;
+		if (is_system_labeled()) {
+			zone = crgetzone(cr);
+			addrtype = tsol_mlp_addr_type(zone->zone_id,
+			    IPV6_VERSION, &v6addr);
+			if (addrtype == mlptSingle) {
+				tcp_err_ack(tcp, mp, TNOADDR, 0);
+				return;
+			}
+			mlptype = tsol_mlp_port_type(zone, IPPROTO_TCP,
+			    requested_port, addrtype);
+		}
+	}
+
+	if (mlptype != mlptSingle) {
+		if (secpolicy_net_bindmlp(cr) != 0) {
+			if (tcp->tcp_debug) {
+				(void) strlog(TCP_MOD_ID, 0, 1,
+				    SL_ERROR|SL_TRACE,
+				    "tcp_bind: no priv for multilevel port %d",
+				    requested_port);
+			}
+			tcp_err_ack(tcp, mp, TACCES, 0);
+			return;
+		}
+
+		/*
+		 * If we're specifically binding a shared IP address and the
+		 * port is MLP on shared addresses, then check to see if this
+		 * zone actually owns the MLP.  Reject if not.
+		 */
+		if (mlptype == mlptShared && addrtype == mlptShared) {
+			zoneid_t mlpzone;
+
+			mlpzone = tsol_mlp_findzone(IPPROTO_TCP,
+			    htons(mlp_port));
+			if (connp->conn_zoneid != mlpzone) {
+				if (tcp->tcp_debug) {
+					(void) strlog(TCP_MOD_ID, 0, 1,
+					    SL_ERROR|SL_TRACE,
+					    "tcp_bind: attempt to bind port "
+					    "%d on shared addr in zone %d "
+					    "(should be %d)",
+					    mlp_port, connp->conn_zoneid,
+					    mlpzone);
+				}
+				tcp_err_ack(tcp, mp, TACCES, 0);
+				return;
+			}
+		}
+
+		if (!user_specified) {
+			err = tsol_mlp_anon(zone, mlptype, connp->conn_ulp,
+			    requested_port, B_TRUE);
+			if (err != 0) {
+				if (tcp->tcp_debug) {
+					(void) strlog(TCP_MOD_ID, 0, 1,
+					    SL_ERROR|SL_TRACE,
+					    "tcp_bind: cannot establish anon "
+					    "MLP for port %d",
+					    requested_port);
+				}
+				tcp_err_ack(tcp, mp, TSYSERR, err);
+				return;
+			}
+			connp->conn_anon_port = B_TRUE;
+		}
+		connp->conn_mlp_type = mlptype;
 	}
 
 	allocated_port = tcp_bindi(tcp, requested_port, &v6addr,
 	    tcp->tcp_reuseaddr, B_FALSE, bind_to_req_port_only, user_specified);
 
 	if (allocated_port == 0) {
+		connp->conn_mlp_type = mlptSingle;
+		if (connp->conn_anon_port) {
+			connp->conn_anon_port = B_FALSE;
+			(void) tsol_mlp_anon(zone, mlptype, connp->conn_ulp,
+			    requested_port, B_FALSE);
+		}
 		if (bind_to_req_port_only) {
 			if (tcp->tcp_debug) {
 				(void) strlog(TCP_MOD_ID, 0, 1,
@@ -3227,7 +3351,13 @@
 			    IPV6_ADDR_LEN);
 		}
 	}
-	if (!mp1) {
+	if (mp1 == NULL) {
+		if (connp->conn_anon_port) {
+			connp->conn_anon_port = B_FALSE;
+			(void) tsol_mlp_anon(zone, mlptype, connp->conn_ulp,
+			    requested_port, B_FALSE);
+		}
+		connp->conn_mlp_type = mlptSingle;
 		tcp_err_ack(tcp, mp, TSYSERR, ENOMEM);
 		return;
 	}
@@ -3314,7 +3444,8 @@
 	int count = 0;
 	/* maximum number of times to run around the loop */
 	int loopmax;
-	zoneid_t zoneid = tcp->tcp_connp->conn_zoneid;
+	conn_t *connp = tcp->tcp_connp;
+	zoneid_t zoneid = connp->conn_zoneid;
 
 	/*
 	 * Lookup for free addresses is done in a loop and "loopmax"
@@ -3349,6 +3480,7 @@
 		uint16_t	lport;
 		tf_t		*tbf;
 		tcp_t		*ltcp;
+		conn_t		*lconnp;
 
 		lport = htons(port);
 
@@ -3368,10 +3500,21 @@
 		mutex_enter(&tbf->tf_lock);
 		for (ltcp = tbf->tf_tcp; ltcp != NULL;
 		    ltcp = ltcp->tcp_bind_hash) {
-			if (lport != ltcp->tcp_lport ||
-			    ltcp->tcp_connp->conn_zoneid != zoneid) {
+			if (lport != ltcp->tcp_lport)
 				continue;
-			}
+
+			lconnp = ltcp->tcp_connp;
+
+			/*
+			 * On a labeled system, we must treat bindings to ports
+			 * on shared IP addresses by sockets with MAC exemption
+			 * privilege as being in all zones, as there's
+			 * otherwise no way to identify the right receiver.
+			 */
+			if (lconnp->conn_zoneid != zoneid &&
+			    !lconnp->conn_mac_exempt &&
+			    !connp->conn_mac_exempt)
+				continue;
 
 			/*
 			 * If TCP_EXCLBIND is set for either the bound or
@@ -3389,6 +3532,9 @@
 			 * spec		unspec		no
 			 * spec		spec		yes if A
 			 *
+			 * For labeled systems, SO_MAC_EXEMPT behaves the same
+			 * as UDP_EXCLBIND, except that zoneid is ignored.
+			 *
 			 * Note:
 			 *
 			 * 1. Because of TLI semantics, an endpoint can go
@@ -3416,7 +3562,8 @@
 			 * in future, we can change this going back semantics,
 			 * we can add the above check.
 			 */
-			if (ltcp->tcp_exclbind || tcp->tcp_exclbind) {
+			if (ltcp->tcp_exclbind || tcp->tcp_exclbind ||
+			    lconnp->conn_mac_exempt || connp->conn_mac_exempt) {
 				if (V6_OR_V4_INADDR_ANY(
 				    ltcp->tcp_bound_source_v6) ||
 				    V6_OR_V4_INADDR_ANY(*laddr) ||
@@ -3538,7 +3685,7 @@
 		}
 
 		if (tcp->tcp_anon_priv_bind) {
-			port = tcp_get_next_priv_port();
+			port = tcp_get_next_priv_port(tcp);
 		} else {
 			if (count == 0 && user_specified) {
 				/*
@@ -3547,12 +3694,15 @@
 				 */
 				port =
 				    tcp_update_next_port(tcp_next_port_to_try,
-					B_TRUE);
+					tcp, B_TRUE);
 				user_specified = B_FALSE;
 			} else {
-				port = tcp_update_next_port(port + 1, B_FALSE);
-			}
-		}
+				port = tcp_update_next_port(port + 1, tcp,
+				    B_FALSE);
+			}
+		}
+		if (port == 0)
+			break;
 
 		/*
 		 * Don't let this loop run forever in the case where
@@ -3821,9 +3971,6 @@
 	qprocsoff(q);
 	inet_minor_free(ip_minor_arena, connp->conn_dev);
 
-	ASSERT(connp->conn_cred != NULL);
-	crfree(connp->conn_cred);
-	tcp->tcp_cred = connp->conn_cred = NULL;
 	tcp->tcp_cpid = -1;
 
 	/*
@@ -4327,31 +4474,9 @@
 	ASSERT(tcp->tcp_rthdrlen == 0);
 
 	ipp = &tcp->tcp_sticky_ipp;
-	if ((ipp->ipp_fields & (IPPF_HOPOPTS | IPPF_RTDSTOPTS |
-	    IPPF_DSTOPTS | IPPF_RTHDR)) != 0) {
-		if ((ipp->ipp_fields & IPPF_HOPOPTS) != 0) {
-			kmem_free(ipp->ipp_hopopts, ipp->ipp_hopoptslen);
-			ipp->ipp_hopopts = NULL;
-			ipp->ipp_hopoptslen = 0;
-		}
-		if ((ipp->ipp_fields & IPPF_RTDSTOPTS) != 0) {
-			kmem_free(ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen);
-			ipp->ipp_rtdstopts = NULL;
-			ipp->ipp_rtdstoptslen = 0;
-		}
-		if ((ipp->ipp_fields & IPPF_DSTOPTS) != 0) {
-			kmem_free(ipp->ipp_dstopts, ipp->ipp_dstoptslen);
-			ipp->ipp_dstopts = NULL;
-			ipp->ipp_dstoptslen = 0;
-		}
-		if ((ipp->ipp_fields & IPPF_RTHDR) != 0) {
-			kmem_free(ipp->ipp_rthdr, ipp->ipp_rthdrlen);
-			ipp->ipp_rthdr = NULL;
-			ipp->ipp_rthdrlen = 0;
-		}
-		ipp->ipp_fields &= ~(IPPF_HOPOPTS | IPPF_RTDSTOPTS |
-		    IPPF_DSTOPTS | IPPF_RTHDR);
-	}
+	if (ipp->ipp_fields & (IPPF_HOPOPTS | IPPF_RTDSTOPTS | IPPF_DSTOPTS |
+	    IPPF_RTHDR))
+		ip6_pkt_free(ipp);
 
 	/*
 	 * Free memory associated with the tcp/ip header template.
@@ -5096,6 +5221,59 @@
 	return ((void *)connp);
 }
 
+/*
+ * Update the cached label for the given tcp_t.  This should be called once per
+ * connection, and before any packets are sent or tcp_process_options is
+ * invoked.  Returns B_FALSE if the correct label could not be constructed.
+ */
+static boolean_t
+tcp_update_label(tcp_t *tcp, const cred_t *cr)
+{
+	conn_t *connp = tcp->tcp_connp;
+
+	if (tcp->tcp_ipversion == IPV4_VERSION) {
+		uchar_t optbuf[IP_MAX_OPT_LENGTH];
+		int added;
+
+		if (tsol_compute_label(cr, tcp->tcp_remote, optbuf,
+		    connp->conn_mac_exempt) != 0)
+			return (B_FALSE);
+
+		added = tsol_remove_secopt(tcp->tcp_ipha, tcp->tcp_hdr_len);
+		if (added == -1)
+			return (B_FALSE);
+		tcp->tcp_hdr_len += added;
+		tcp->tcp_tcph = (tcph_t *)((uchar_t *)tcp->tcp_tcph + added);
+		tcp->tcp_ip_hdr_len += added;
+		if ((tcp->tcp_label_len = optbuf[IPOPT_OLEN]) != 0) {
+			tcp->tcp_label_len = (tcp->tcp_label_len + 3) & ~3;
+			added = tsol_prepend_option(optbuf, tcp->tcp_ipha,
+			    tcp->tcp_hdr_len);
+			if (added == -1)
+				return (B_FALSE);
+			tcp->tcp_hdr_len += added;
+			tcp->tcp_tcph = (tcph_t *)
+			    ((uchar_t *)tcp->tcp_tcph + added);
+			tcp->tcp_ip_hdr_len += added;
+		}
+	} else {
+		uchar_t optbuf[TSOL_MAX_IPV6_OPTION];
+
+		if (tsol_compute_label_v6(cr, &tcp->tcp_remote_v6, optbuf,
+		    connp->conn_mac_exempt) != 0)
+			return (B_FALSE);
+		if (tsol_update_sticky(&tcp->tcp_sticky_ipp,
+		    &tcp->tcp_label_len, optbuf) != 0)
+			return (B_FALSE);
+		if (tcp_build_hdrs(tcp->tcp_rq, tcp) != 0)
+			return (B_FALSE);
+	}
+
+	connp->conn_ulp_labeled = 1;
+
+	return (B_TRUE);
+}
+
 /* BEGIN CSTYLED */
 /*
  *
@@ -5232,6 +5410,7 @@
 	conn_t		*connp = (conn_t *)arg;
 	tcp_t		*tcp = connp->conn_tcp;
 	ire_t		*ire;
+	cred_t		*credp;
 
 	if (tcp->tcp_state != TCPS_LISTEN)
 		goto error2;
@@ -5377,6 +5556,46 @@
 		econnp->conn_nexthop_v4 = connp->conn_nexthop_v4;
 	}
 
+	/*
+	 * TSOL: tsol_input_proc() needs the eager's cred before the
+	 * eager is accepted
+	 */
+	econnp->conn_cred = eager->tcp_cred = credp = connp->conn_cred;
+	crhold(credp);
+
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		econnp->conn_mac_exempt = B_TRUE;
+
+	if (is_system_labeled()) {
+		cred_t *cr;
+
+		if (connp->conn_mlp_type != mlptSingle) {
+			cr = econnp->conn_peercred = DB_CRED(mp);
+			if (cr != NULL)
+				crhold(cr);
+			else
+				cr = econnp->conn_cred;
+			DTRACE_PROBE2(mlp_syn_accept, conn_t *,
+			    econnp, cred_t *, cr)
+		} else {
+			cr = econnp->conn_cred;
+			DTRACE_PROBE2(syn_accept, conn_t *,
+			    econnp, cred_t *, cr)
+		}
+
+		if (!tcp_update_label(eager, cr)) {
+			DTRACE_PROBE3(
+			    tx__ip__log__error__connrequest__tcp,
+			    char *, "eager connp(1) label on SYN mp(2) failed",
+			    conn_t *, econnp, mblk_t *, mp);
+			goto error3;
+		}
+	}
+
 	eager->tcp_hard_binding = B_TRUE;
 
 	tcp_bind_hash_insert(&tcp_bind_fanout[
@@ -5530,7 +5749,6 @@
 	    NULL, NULL, eager->tcp_iss, B_FALSE, NULL, B_FALSE);
 	if (mp1 == NULL)
 		goto error1;
-	mblk_setcred(mp1, tcp->tcp_cred);
 	DB_CPID(mp1) = tcp->tcp_cpid;
 
 	/*
@@ -6107,7 +6325,7 @@
 		 * tcp_bindi will pick an unused port, insert the connection
 		 * in the bind hash and transition to BOUND state.
 		 */
-		lport = tcp_update_next_port(tcp_next_port_to_try, B_TRUE);
+		lport = tcp_update_next_port(tcp_next_port_to_try, tcp, B_TRUE);
 		lport = tcp_bindi(tcp, lport, &tcp->tcp_ip_src_v6, 0, B_TRUE,
 		    B_FALSE, B_FALSE);
 		if (lport == 0) {
@@ -6140,6 +6358,7 @@
 	if (mp1) {
 		/* Hang onto the T_OK_ACK for later. */
 		linkb(mp1, mp);
+		mblk_setcred(mp1, tcp->tcp_cred);
 		if (tcp->tcp_family == AF_INET)
 			mp1 = ip_bind_v4(tcp->tcp_wq, mp1, tcp->tcp_connp);
 		else {
@@ -6304,7 +6523,7 @@
 		 * tcp_bindi will pick an unused port, insert the connection
 		 * in the bind hash and transition to BOUND state.
 		 */
-		lport = tcp_update_next_port(tcp_next_port_to_try, B_TRUE);
+		lport = tcp_update_next_port(tcp_next_port_to_try, tcp, B_TRUE);
 		lport = tcp_bindi(tcp, lport, &tcp->tcp_ip_src_v6, 0, B_TRUE,
 		    B_FALSE, B_FALSE);
 		if (lport == 0) {
@@ -6330,6 +6549,7 @@
 	if (mp1) {
 		/* Hang onto the T_OK_ACK for later. */
 		linkb(mp1, mp);
+		mblk_setcred(mp1, tcp->tcp_cred);
 		mp1 = ip_bind_v6(tcp->tcp_wq, mp1, tcp->tcp_connp,
 		    &tcp->tcp_sticky_ipp);
 		BUMP_MIB(&tcp_mib, tcpActiveOpens);
@@ -7798,6 +8018,7 @@
 {
 	tcph_t		*tcph;
 	uint32_t	sum;
+	conn_t		*connp;
 
 	/*
 	 * This is a simple initialization. If there's
@@ -7813,6 +8034,11 @@
 			return (ENOMEM);
 		}
 	}
+
+	/* options are gone; may need a new label */
+	connp = tcp->tcp_connp;
+	connp->conn_mlp_type = mlptSingle;
+	connp->conn_ulp_labeled = !is_system_labeled();
 	ASSERT(tcp->tcp_iphc_len >= TCP_MAX_COMBINED_HEADER_LENGTH);
 	tcp->tcp_ipha = (ipha_t *)tcp->tcp_iphc;
 	tcp->tcp_ip6h = NULL;
@@ -7854,6 +8080,7 @@
 {
 	tcph_t	*tcph;
 	uint32_t	sum;
+	conn_t	*connp;
 
 	/*
 	 * This is a simple initialization. If there's
@@ -7877,6 +8104,12 @@
 			return (ENOMEM);
 		}
 	}
+
+	/* options are gone; may need a new label */
+	connp = tcp->tcp_connp;
+	connp->conn_mlp_type = mlptSingle;
+	connp->conn_ulp_labeled = !is_system_labeled();
+
 	ASSERT(tcp->tcp_iphc_len >= TCP_MAX_COMBINED_HEADER_LENGTH);
 	tcp->tcp_ipversion = IPV6_VERSION;
 	tcp->tcp_hdr_len = IPV6_HDR_LEN + sizeof (tcph_t);
@@ -9147,6 +9380,15 @@
 	crhold(connp->conn_cred);
 	tcp->tcp_cpid = curproc->p_pid;
 	connp->conn_zoneid = zoneid;
+	connp->conn_mlp_type = mlptSingle;
+	connp->conn_ulp_labeled = !is_system_labeled();
+
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		connp->conn_mac_exempt = B_TRUE;
 
 	connp->conn_dev = conn_dev;
 
@@ -9345,6 +9587,12 @@
 			*i1 = tcp->tcp_snd_zcopy_on ?
 			    SO_SND_COPYAVOID : 0;
 			break;
+		case SO_ANON_MLP:
+			*i1 = connp->conn_anon_mlp;
+			break;
+		case SO_MAC_EXEMPT:
+			*i1 = connp->conn_mac_exempt;
+			break;
 		default:
 			return (-1);
 		}
@@ -9406,17 +9654,18 @@
 			 * as the last entry. The first 4 bytes of the option
 			 * will contain the final destination.
 			 */
-			char	*opt_ptr;
 			int	opt_len;
-			opt_ptr = (char *)tcp->tcp_ipha + IP_SIMPLE_HDR_LENGTH;
-			opt_len = (char *)tcp->tcp_tcph - opt_ptr;
+
+			opt_len = (char *)tcp->tcp_tcph - (char *)tcp->tcp_ipha;
+			opt_len -= tcp->tcp_label_len + IP_SIMPLE_HDR_LENGTH;
+			ASSERT(opt_len >= 0);
 			/* Caller ensures enough space */
 			if (opt_len > 0) {
 				/*
 				 * TODO: Do we have to handle getsockopt on an
 				 * initiator as well?
 				 */
-				return (tcp_opt_get_user(tcp->tcp_ipha, ptr));
+				return (ip_opt_get_user(tcp->tcp_ipha, ptr));
 			}
 			return (0);
 			}
@@ -9536,8 +9785,16 @@
 		case IPV6_HOPOPTS:
 			if (!(ipp->ipp_fields & IPPF_HOPOPTS))
 				return (0);
-			bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen);
-			return (ipp->ipp_hopoptslen);
+			if (ipp->ipp_hopoptslen <= tcp->tcp_label_len)
+				return (0);
+			bcopy((char *)ipp->ipp_hopopts + tcp->tcp_label_len,
+			    ptr, ipp->ipp_hopoptslen - tcp->tcp_label_len);
+			if (tcp->tcp_label_len > 0) {
+				ptr[0] = ((char *)ipp->ipp_hopopts)[0];
+				ptr[1] = (ipp->ipp_hopoptslen -
+				    tcp->tcp_label_len + 7) / 8 - 1;
+			}
+			return (ipp->ipp_hopoptslen - tcp->tcp_label_len);
 		case IPV6_RTHDRDSTOPTS:
 			if (!(ipp->ipp_fields & IPPF_RTDSTOPTS))
 				return (0);
@@ -9585,7 +9842,8 @@
     uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
     void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
 {
-	tcp_t	*tcp = Q_TO_TCP(q);
+	conn_t	*connp = Q_TO_CONN(q);
+	tcp_t	*tcp = connp->conn_tcp;
 	int	*i1 = (int *)invalp;
 	boolean_t onoff = (*i1 == 0) ? 0 : 1;
 	boolean_t checkonly;
@@ -9713,7 +9971,7 @@
 			break;
 		case SO_DONTROUTE:
 			/*
-			 * SO_DONTROUTE, SO_USELOOPBACK and SO_BROADCAST are
+			 * SO_DONTROUTE, SO_USELOOPBACK, and SO_BROADCAST are
 			 * only of interest to IP.  We track them here only so
 			 * that we can report their current value.
 			 */
@@ -9814,6 +10072,23 @@
 				tcp->tcp_snd_zcopy_aware = 1;
 			}
 			break;
+		case SO_ANON_MLP:
+			if (!checkonly) {
+				mutex_enter(&connp->conn_lock);
+				connp->conn_anon_mlp = onoff;
+				mutex_exit(&connp->conn_lock);
+			}
+			break;
+		case SO_MAC_EXEMPT:
+			if (secpolicy_net_mac_aware(cr) != 0 ||
+			    IPCL_IS_BOUND(connp))
+				return (EACCES);
+			if (!checkonly) {
+				mutex_enter(&connp->conn_lock);
+				connp->conn_mac_exempt = onoff;
+				mutex_exit(&connp->conn_lock);
+			}
+			break;
 		default:
 			*outlenp = 0;
 			return (EINVAL);
@@ -10241,6 +10516,7 @@
 			break;
 		case IPV6_HOPOPTS: {
 			ip6_hbh_t *hopts = (ip6_hbh_t *)invalp;
+
 			/*
 			 * Sanity checks - minimum size, size a multiple of
 			 * eight bytes, and matching size passed in.
@@ -10252,22 +10528,15 @@
 			if (checkonly)
 				break;
 
-			if (inlen == 0) {
-				if ((ipp->ipp_fields & IPPF_HOPOPTS) != 0) {
-					kmem_free(ipp->ipp_hopopts,
-					    ipp->ipp_hopoptslen);
-					ipp->ipp_hopopts = NULL;
-					ipp->ipp_hopoptslen = 0;
-				}
+			reterr = optcom_pkt_set(invalp, inlen, B_TRUE,
+			    (uchar_t **)&ipp->ipp_hopopts,
+			    &ipp->ipp_hopoptslen, tcp->tcp_label_len);
+			if (reterr != 0)
+				return (reterr);
+			if (ipp->ipp_hopoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
-			} else {
-				reterr = tcp_pkt_set(invalp, inlen,
-				    (uchar_t **)&ipp->ipp_hopopts,
-				    &ipp->ipp_hopoptslen);
-				if (reterr != 0)
-					return (reterr);
+			else
 				ipp->ipp_fields |= IPPF_HOPOPTS;
-			}
 			reterr = tcp_build_hdrs(q, tcp);
 			if (reterr != 0)
 				return (reterr);
@@ -10287,22 +10556,15 @@
 			if (checkonly)
 				break;
 
-			if (inlen == 0) {
-				if ((ipp->ipp_fields & IPPF_RTDSTOPTS) != 0) {
-					kmem_free(ipp->ipp_rtdstopts,
-					    ipp->ipp_rtdstoptslen);
-					ipp->ipp_rtdstopts = NULL;
-					ipp->ipp_rtdstoptslen = 0;
-				}
+			reterr = optcom_pkt_set(invalp, inlen, B_TRUE,
+			    (uchar_t **)&ipp->ipp_rtdstopts,
+			    &ipp->ipp_rtdstoptslen, 0);
+			if (reterr != 0)
+				return (reterr);
+			if (ipp->ipp_rtdstoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
-			} else {
-				reterr = tcp_pkt_set(invalp, inlen,
-				    (uchar_t **)&ipp->ipp_rtdstopts,
-				    &ipp->ipp_rtdstoptslen);
-				if (reterr != 0)
-					return (reterr);
+			else
 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
-			}
 			reterr = tcp_build_hdrs(q, tcp);
 			if (reterr != 0)
 				return (reterr);
@@ -10322,22 +10584,15 @@
 			if (checkonly)
 				break;
 
-			if (inlen == 0) {
-				if ((ipp->ipp_fields & IPPF_DSTOPTS) != 0) {
-					kmem_free(ipp->ipp_dstopts,
-					    ipp->ipp_dstoptslen);
-					ipp->ipp_dstopts = NULL;
-					ipp->ipp_dstoptslen = 0;
-				}
+			reterr = optcom_pkt_set(invalp, inlen, B_TRUE,
+			    (uchar_t **)&ipp->ipp_dstopts,
+			    &ipp->ipp_dstoptslen, 0);
+			if (reterr != 0)
+				return (reterr);
+			if (ipp->ipp_dstoptslen == 0)
 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
-			} else {
-				reterr = tcp_pkt_set(invalp, inlen,
-				    (uchar_t **)&ipp->ipp_dstopts,
-				    &ipp->ipp_dstoptslen);
-				if (reterr != 0)
-					return (reterr);
+			else
 				ipp->ipp_fields |= IPPF_DSTOPTS;
-			}
 			reterr = tcp_build_hdrs(q, tcp);
 			if (reterr != 0)
 				return (reterr);
@@ -10357,22 +10612,15 @@
 			if (checkonly)
 				break;
 
-			if (inlen == 0) {
-				if ((ipp->ipp_fields & IPPF_RTHDR) != 0) {
-					kmem_free(ipp->ipp_rthdr,
-					    ipp->ipp_rthdrlen);
-					ipp->ipp_rthdr = NULL;
-					ipp->ipp_rthdrlen = 0;
-				}
+			reterr = optcom_pkt_set(invalp, inlen, B_TRUE,
+			    (uchar_t **)&ipp->ipp_rthdr,
+			    &ipp->ipp_rthdrlen, 0);
+			if (reterr != 0)
+				return (reterr);
+			if (ipp->ipp_rthdrlen == 0)
 				ipp->ipp_fields &= ~IPPF_RTHDR;
-			} else {
-				reterr = tcp_pkt_set(invalp, inlen,
-				    (uchar_t **)&ipp->ipp_rthdr,
-				    &ipp->ipp_rthdrlen);
-				if (reterr != 0)
-					return (reterr);
+			else
 				ipp->ipp_fields |= IPPF_RTHDR;
-			}
 			reterr = tcp_build_hdrs(q, tcp);
 			if (reterr != 0)
 				return (reterr);
@@ -10545,116 +10793,6 @@
 }
 
 /*
- * Set optbuf and optlen for the option.
- * Allocate memory (if not already present).
- * Otherwise just point optbuf and optlen at invalp and inlen.
- * Returns failure if memory can not be allocated.
- */
-static int
-tcp_pkt_set(uchar_t *invalp, uint_t inlen, uchar_t **optbufp, uint_t *optlenp)
-{
-	uchar_t *optbuf;
-
-	if (inlen == *optlenp) {
-		/* Unchanged length - no need to realocate */
-		bcopy(invalp, *optbufp, inlen);
-		return (0);
-	}
-	if (inlen != 0) {
-		/* Allocate new buffer before free */
-		optbuf = kmem_alloc(inlen, KM_NOSLEEP);
-		if (optbuf == NULL)
-			return (ENOMEM);
-	} else {
-		optbuf = NULL;
-	}
-	/* Free old buffer */
-	if (*optlenp != 0)
-		kmem_free(*optbufp, *optlenp);
-
-	bcopy(invalp, optbuf, inlen);
-	*optbufp = optbuf;
-	*optlenp = inlen;
-	return (0);
-}
-
-
-/*
- * Use the outgoing IP header to create an IP_OPTIONS option the way
- * it was passed down from the application.
- */
-static int
-tcp_opt_get_user(ipha_t *ipha, uchar_t *buf)
-{
-	ipoptp_t	opts;
-	uchar_t		*opt;
-	uint8_t		optval;
-	uint8_t		optlen;
-	uint32_t	len = 0;
-	uchar_t	*buf1 = buf;
-
-	buf += IP_ADDR_LEN;	/* Leave room for final destination */
-	len += IP_ADDR_LEN;
-	bzero(buf1, IP_ADDR_LEN);
-
-	for (optval = ipoptp_first(&opts, ipha);
-	    optval != IPOPT_EOL;
-	    optval = ipoptp_next(&opts)) {
-		opt = opts.ipoptp_cur;
-		optlen = opts.ipoptp_len;
-		switch (optval) {
-			int	off;
-		case IPOPT_SSRR:
-		case IPOPT_LSRR:
-
-			/*
-			 * Insert ipha_dst as the first entry in the source
-			 * route and move down the entries on step.
-			 * The last entry gets placed at buf1.
-			 */
-			buf[IPOPT_OPTVAL] = optval;
-			buf[IPOPT_OLEN] = optlen;
-			buf[IPOPT_OFFSET] = optlen;
-
-			off = optlen - IP_ADDR_LEN;
-			if (off < 0) {
-				/* No entries in source route */
-				break;
-			}
-			/* Last entry in source route */
-			bcopy(opt + off, buf1, IP_ADDR_LEN);
-			off -= IP_ADDR_LEN;
-
-			while (off > 0) {
-				bcopy(opt + off,
-				    buf + off + IP_ADDR_LEN,
-				    IP_ADDR_LEN);
-				off -= IP_ADDR_LEN;
-			}
-			/* ipha_dst into first slot */
-			bcopy(&ipha->ipha_dst,
-			    buf + off + IP_ADDR_LEN,
-			    IP_ADDR_LEN);
-			buf += optlen;
-			len += optlen;
-			break;
-		default:
-			bcopy(opt, buf, optlen);
-			buf += optlen;
-			len += optlen;
-			break;
-		}
-	}
-done:
-	/* Pad the resulting options */
-	while (len & 0x3) {
-		*buf++ = IPOPT_EOL;
-		len++;
-	}
-	return (len);
-}
-
-/*
  * Transfer any source route option from ipha to buf/dst in reversed form.
  */
 static int
@@ -10774,41 +10912,46 @@
 tcp_opt_set_header(tcp_t *tcp, boolean_t checkonly, uchar_t *ptr, uint_t len)
 {
 	uint_t	tcph_len;
-	char	*ip_optp;
+	uint8_t	*ip_optp;
 	tcph_t	*new_tcph;
 
+	if ((len > TCP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
+		return (EINVAL);
+
+	if (len > IP_MAX_OPT_LENGTH - tcp->tcp_label_len)
+		return (EINVAL);
+
 	if (checkonly) {
 		/*
 		 * do not really set, just pretend to - T_CHECK
 		 */
-		if (len != 0) {
-			/*
-			 * there is value supplied, validate it as if
-			 * for a real set operation.
-			 */
-			if ((len > TCP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
-				return (EINVAL);
-		}
 		return (0);
 	}
 
-	if ((len > TCP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3))
-		return (EINVAL);
-
-	ip_optp = (char *)tcp->tcp_ipha + IP_SIMPLE_HDR_LENGTH;
+	ip_optp = (uint8_t *)tcp->tcp_ipha + IP_SIMPLE_HDR_LENGTH;
+	if (tcp->tcp_label_len > 0) {
+		int padlen;
+		uint8_t opt;
+
+		/* convert list termination to no-ops */
+		padlen = tcp->tcp_label_len - ip_optp[IPOPT_OLEN];
+		ip_optp += ip_optp[IPOPT_OLEN];
+		opt = len > 0 ? IPOPT_NOP : IPOPT_EOL;
+		while (--padlen >= 0)
+			*ip_optp++ = opt;
+	}
 	tcph_len = tcp->tcp_tcp_hdr_len;
 	new_tcph = (tcph_t *)(ip_optp + len);
-	ovbcopy((char *)tcp->tcp_tcph, (char *)new_tcph, tcph_len);
+	ovbcopy(tcp->tcp_tcph, new_tcph, tcph_len);
 	tcp->tcp_tcph = new_tcph;
 	bcopy(ptr, ip_optp, len);
 
-	len += IP_SIMPLE_HDR_LENGTH;
+	len += IP_SIMPLE_HDR_LENGTH + tcp->tcp_label_len;
 
 	tcp->tcp_ip_hdr_len = len;
 	tcp->tcp_ipha->ipha_version_and_hdr_length =
-		(IP_VERSION << 4) | (len >> 2);
-	len += tcph_len;
-	tcp->tcp_hdr_len = len;
+	    (IP_VERSION << 4) | (len >> 2);
+	tcp->tcp_hdr_len = len + tcph_len;
 	if (!TCP_IS_DETACHED(tcp)) {
 		/* Always allocate room for all options. */
 		(void) mi_set_sth_wroff(tcp->tcp_rq,
@@ -12601,7 +12744,6 @@
 		mp1 = tcp_xmit_mp(tcp, tcp->tcp_xmit_head, tcp->tcp_mss,
 		    NULL, NULL, tcp->tcp_iss, B_FALSE, NULL, B_FALSE);
 		if (mp1) {
-			mblk_setcred(mp1, tcp->tcp_cred);
 			DB_CPID(mp1) = tcp->tcp_cpid;
 			TCP_RECORD_TRACE(tcp, mp1, TCP_TRACE_SEND_PKT);
 			tcp_send_data(tcp, tcp->tcp_wq, mp1);
@@ -14723,57 +14865,59 @@
 		optlen += sizeof (struct T_opthdr) + sizeof (uint_t);
 		addflag |= TCP_IPV6_RECVTCLASS;
 	}
-	/* If app asked for hopbyhop headers and it has changed ... */
+	/*
+	 * If app asked for hopbyhop headers and it has changed ...
+	 * For security labels, note that (1) security labels can't change on
+	 * a connected socket at all, (2) we're connected to at most one peer,
+	 * (3) if anything changes, then it must be some other extra option.
+	 */
 	if ((tcp->tcp_ipv6_recvancillary & TCP_IPV6_RECVHOPOPTS) &&
-	    tcp_cmpbuf(tcp->tcp_hopopts, tcp->tcp_hopoptslen,
-		(ipp->ipp_fields & IPPF_HOPOPTS),
-		ipp->ipp_hopopts, ipp->ipp_hopoptslen)) {
-		optlen += sizeof (struct T_opthdr) + ipp->ipp_hopoptslen;
+	    ip_cmpbuf(tcp->tcp_hopopts, tcp->tcp_hopoptslen,
+	    (ipp->ipp_fields & IPPF_HOPOPTS),
+	    ipp->ipp_hopopts, ipp->ipp_hopoptslen)) {
+		optlen += sizeof (struct T_opthdr) + ipp->ipp_hopoptslen -
+		    tcp->tcp_label_len;
 		addflag |= TCP_IPV6_RECVHOPOPTS;
-		if (!tcp_allocbuf((void **)&tcp->tcp_hopopts,
-		    &tcp->tcp_hopoptslen,
-		    (ipp->ipp_fields & IPPF_HOPOPTS),
+		if (!ip_allocbuf((void **)&tcp->tcp_hopopts,
+		    &tcp->tcp_hopoptslen, (ipp->ipp_fields & IPPF_HOPOPTS),
 		    ipp->ipp_hopopts, ipp->ipp_hopoptslen))
 			return (mp);
 	}
 	/* If app asked for dst headers before routing headers ... */
 	if ((tcp->tcp_ipv6_recvancillary & TCP_IPV6_RECVRTDSTOPTS) &&
-	    tcp_cmpbuf(tcp->tcp_rtdstopts, tcp->tcp_rtdstoptslen,
+	    ip_cmpbuf(tcp->tcp_rtdstopts, tcp->tcp_rtdstoptslen,
 		(ipp->ipp_fields & IPPF_RTDSTOPTS),
 		ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen)) {
 		optlen += sizeof (struct T_opthdr) +
 		    ipp->ipp_rtdstoptslen;
 		addflag |= TCP_IPV6_RECVRTDSTOPTS;
-		if (!tcp_allocbuf((void **)&tcp->tcp_rtdstopts,
-		    &tcp->tcp_rtdstoptslen,
-		    (ipp->ipp_fields & IPPF_RTDSTOPTS),
+		if (!ip_allocbuf((void **)&tcp->tcp_rtdstopts,
+		    &tcp->tcp_rtdstoptslen, (ipp->ipp_fields & IPPF_RTDSTOPTS),
 		    ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen))
 			return (mp);
 	}
 	/* If app asked for routing headers and it has changed ... */
 	if ((tcp->tcp_ipv6_recvancillary & TCP_IPV6_RECVRTHDR) &&
-	    tcp_cmpbuf(tcp->tcp_rthdr, tcp->tcp_rthdrlen,
-		(ipp->ipp_fields & IPPF_RTHDR),
-		ipp->ipp_rthdr, ipp->ipp_rthdrlen)) {
+	    ip_cmpbuf(tcp->tcp_rthdr, tcp->tcp_rthdrlen,
+	    (ipp->ipp_fields & IPPF_RTHDR),
+	    ipp->ipp_rthdr, ipp->ipp_rthdrlen)) {
 		optlen += sizeof (struct T_opthdr) + ipp->ipp_rthdrlen;
 		addflag |= TCP_IPV6_RECVRTHDR;
-		if (!tcp_allocbuf((void **)&tcp->tcp_rthdr,
-		    &tcp->tcp_rthdrlen,
-		    (ipp->ipp_fields & IPPF_RTHDR),
+		if (!ip_allocbuf((void **)&tcp->tcp_rthdr,
+		    &tcp->tcp_rthdrlen, (ipp->ipp_fields & IPPF_RTHDR),
 		    ipp->ipp_rthdr, ipp->ipp_rthdrlen))
 			return (mp);
 	}
 	/* If app asked for dest headers and it has changed ... */
 	if ((tcp->tcp_ipv6_recvancillary &
-		(TCP_IPV6_RECVDSTOPTS | TCP_OLD_IPV6_RECVDSTOPTS)) &&
-	    tcp_cmpbuf(tcp->tcp_dstopts, tcp->tcp_dstoptslen,
-		(ipp->ipp_fields & IPPF_DSTOPTS),
-		ipp->ipp_dstopts, ipp->ipp_dstoptslen)) {
+	    (TCP_IPV6_RECVDSTOPTS | TCP_OLD_IPV6_RECVDSTOPTS)) &&
+	    ip_cmpbuf(tcp->tcp_dstopts, tcp->tcp_dstoptslen,
+	    (ipp->ipp_fields & IPPF_DSTOPTS),
+	    ipp->ipp_dstopts, ipp->ipp_dstoptslen)) {
 		optlen += sizeof (struct T_opthdr) + ipp->ipp_dstoptslen;
 		addflag |= TCP_IPV6_RECVDSTOPTS;
-		if (!tcp_allocbuf((void **)&tcp->tcp_dstopts,
-		    &tcp->tcp_dstoptslen,
-		    (ipp->ipp_fields & IPPF_DSTOPTS),
+		if (!ip_allocbuf((void **)&tcp->tcp_dstopts,
+		    &tcp->tcp_dstoptslen, (ipp->ipp_fields & IPPF_DSTOPTS),
 		    ipp->ipp_dstopts, ipp->ipp_dstoptslen))
 			return (mp);
 	}
@@ -14857,15 +15001,16 @@
 		toh = (struct T_opthdr *)optptr;
 		toh->level = IPPROTO_IPV6;
 		toh->name = IPV6_HOPOPTS;
-		toh->len = sizeof (*toh) + ipp->ipp_hopoptslen;
+		toh->len = sizeof (*toh) + ipp->ipp_hopoptslen -
+		    tcp->tcp_label_len;
 		toh->status = 0;
 		optptr += sizeof (*toh);
-		bcopy(ipp->ipp_hopopts, optptr, ipp->ipp_hopoptslen);
-		optptr += ipp->ipp_hopoptslen;
+		bcopy((uchar_t *)ipp->ipp_hopopts + tcp->tcp_label_len, optptr,
+		    ipp->ipp_hopoptslen - tcp->tcp_label_len);
+		optptr += ipp->ipp_hopoptslen - tcp->tcp_label_len;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		tcp_savebuf((void **)&tcp->tcp_hopopts,
-		    &tcp->tcp_hopoptslen,
+		ip_savebuf((void **)&tcp->tcp_hopopts, &tcp->tcp_hopoptslen,
 		    (ipp->ipp_fields & IPPF_HOPOPTS),
 		    ipp->ipp_hopopts, ipp->ipp_hopoptslen);
 	}
@@ -14880,7 +15025,7 @@
 		optptr += ipp->ipp_rtdstoptslen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		tcp_savebuf((void **)&tcp->tcp_rtdstopts,
+		ip_savebuf((void **)&tcp->tcp_rtdstopts,
 		    &tcp->tcp_rtdstoptslen,
 		    (ipp->ipp_fields & IPPF_RTDSTOPTS),
 		    ipp->ipp_rtdstopts, ipp->ipp_rtdstoptslen);
@@ -14896,8 +15041,7 @@
 		optptr += ipp->ipp_rthdrlen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		tcp_savebuf((void **)&tcp->tcp_rthdr,
-		    &tcp->tcp_rthdrlen,
+		ip_savebuf((void **)&tcp->tcp_rthdr, &tcp->tcp_rthdrlen,
 		    (ipp->ipp_fields & IPPF_RTHDR),
 		    ipp->ipp_rthdr, ipp->ipp_rthdrlen);
 	}
@@ -14912,8 +15056,7 @@
 		optptr += ipp->ipp_dstoptslen;
 		ASSERT(OK_32PTR(optptr));
 		/* Save as last value */
-		tcp_savebuf((void **)&tcp->tcp_dstopts,
-		    &tcp->tcp_dstoptslen,
+		ip_savebuf((void **)&tcp->tcp_dstopts, &tcp->tcp_dstoptslen,
 		    (ipp->ipp_fields & IPPF_DSTOPTS),
 		    ipp->ipp_dstopts, ipp->ipp_dstoptslen);
 	}
@@ -15094,6 +15237,12 @@
 			if (tcp->tcp_state != TCPS_SYN_SENT)
 				goto after_syn_sent;
 
+			if (is_system_labeled() &&
+			    !tcp_update_label(tcp, CONN_CRED(tcp->tcp_connp))) {
+				tcp_bind_failed(tcp, mp, EHOSTUNREACH);
+				return;
+			}
+
 			ASSERT(q == tcp->tcp_rq);
 			/*
 			 * tcp_adapt_ire() does not adjust
@@ -15162,21 +15311,9 @@
 			syn_mp = tcp_xmit_mp(tcp, NULL, 0, NULL, NULL,
 			    tcp->tcp_iss, B_FALSE, NULL, B_FALSE);
 			if (syn_mp) {
-				cred_t *cr;
 				pid_t pid;
 
-				/*
-				 * Obtain the credential from the
-				 * thread calling connect(); the credential
-				 * lives on in the second mblk which
-				 * originated from T_CONN_REQ and is echoed
-				 * with the T_BIND_ACK from ip.  If none
-				 * can be found, default to the creator
-				 * of the socket.
-				 */
-				if (mp->b_cont == NULL ||
-				    (cr = DB_CRED(mp->b_cont)) == NULL) {
-					cr = tcp->tcp_cred;
+				if (mp->b_cont == NULL) {
 					pid = tcp->tcp_cpid;
 				} else {
 					pid = DB_CPID(mp->b_cont);
@@ -15184,7 +15321,6 @@
 
 				TCP_RECORD_TRACE(tcp, syn_mp,
 				    TCP_TRACE_SEND_PKT);
-				mblk_setcred(syn_mp, cr);
 				DB_CPID(syn_mp) = pid;
 				tcp_send_data(tcp, tcp->tcp_wq, syn_mp);
 			}
@@ -15593,34 +15729,39 @@
 {
 	mblk_t			*mpdata;
 	mblk_t			*mp_conn_ctl = NULL;
-	mblk_t			*mp_conn_data;
+	mblk_t			*mp_conn_tail;
+	mblk_t			*mp_attr_ctl = NULL;
+	mblk_t			*mp_attr_tail;
 	mblk_t			*mp6_conn_ctl = NULL;
-	mblk_t			*mp6_conn_data;
-	mblk_t			*mp_conn_tail = NULL;
-	mblk_t			*mp6_conn_tail = NULL;
+	mblk_t			*mp6_conn_tail;
+	mblk_t			*mp6_attr_ctl = NULL;
+	mblk_t			*mp6_attr_tail;
 	struct opthdr		*optp;
 	mib2_tcpConnEntry_t	tce;
 	mib2_tcp6ConnEntry_t	tce6;
+	mib2_transportMLPEntry_t mlp;
 	connf_t			*connfp;
 	conn_t			*connp;
 	int			i;
 	boolean_t 		ispriv;
 	zoneid_t 		zoneid;
+	int			v4_conn_idx;
+	int			v6_conn_idx;
 
 	if (mpctl == NULL ||
 	    (mpdata = mpctl->b_cont) == NULL ||
 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
-	    (mp6_conn_ctl = copymsg(mpctl)) == NULL) {
-		if (mp_conn_ctl != NULL)
-			freemsg(mp_conn_ctl);
-		if (mp6_conn_ctl != NULL)
-			freemsg(mp6_conn_ctl);
+	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_attr_ctl = copymsg(mpctl)) == NULL) {
+		freemsg(mp_conn_ctl);
+		freemsg(mp_attr_ctl);
+		freemsg(mp6_conn_ctl);
+		freemsg(mp6_attr_ctl);
 		return (0);
 	}
 
 	/* build table of connections -- need count in fixed part */
-	mp_conn_data = mp_conn_ctl->b_cont;
-	mp6_conn_data = mp6_conn_ctl->b_cont;
 	SET_MIB(tcp_mib.tcpRtoAlgorithm, 4);   /* vanj */
 	SET_MIB(tcp_mib.tcpRtoMin, tcp_rexmit_interval_min);
 	SET_MIB(tcp_mib.tcpRtoMax, tcp_rexmit_interval_max);
@@ -15631,6 +15772,9 @@
 	    secpolicy_net_config((Q_TO_CONN(q))->conn_cred, B_TRUE) == 0;
 	zoneid = Q_TO_CONN(q)->conn_zoneid;
 
+	v4_conn_idx = v6_conn_idx = 0;
+	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
+
 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
 
 		connfp = &ipcl_globalhash_fanout[i];
@@ -15640,6 +15784,7 @@
 		while ((connp =
 		    ipcl_get_next_conn(connfp, connp, IPCL_TCP)) != NULL) {
 			tcp_t *tcp;
+			boolean_t needattr;
 
 			if (connp->conn_zoneid != zoneid)
 				continue;	/* not in this zone */
@@ -15656,6 +15801,26 @@
 			    tce.tcpConnState == MIB2_TCP_closeWait)
 				BUMP_MIB(&tcp_mib, tcpCurrEstab);
 
+			needattr = B_FALSE;
+			bzero(&mlp, sizeof (mlp));
+			if (connp->conn_mlp_type != mlptSingle) {
+				if (connp->conn_mlp_type == mlptShared ||
+				    connp->conn_mlp_type == mlptBoth)
+					mlp.tme_flags |= MIB2_TMEF_SHARED;
+				if (connp->conn_mlp_type == mlptPrivate ||
+				    connp->conn_mlp_type == mlptBoth)
+					mlp.tme_flags |= MIB2_TMEF_PRIVATE;
+				needattr = B_TRUE;
+			}
+			if (connp->conn_peercred != NULL) {
+				ts_label_t *tsl;
+
+				tsl = crgetlabel(connp->conn_peercred);
+				mlp.tme_doi = label2doi(tsl);
+				mlp.tme_label = *label2bslabel(tsl);
+				needattr = B_TRUE;
+			}
+
 			/* Create a message to report on IPv6 entries */
 			if (tcp->tcp_ipversion == IPV6_VERSION) {
 			tce6.tcp6ConnLocalAddress = tcp->tcp_ip_src_v6;
@@ -15692,8 +15857,14 @@
 			tce6.tcp6ConnEntryInfo.ce_rto =  tcp->tcp_rto;
 			tce6.tcp6ConnEntryInfo.ce_mss =  tcp->tcp_mss;
 			tce6.tcp6ConnEntryInfo.ce_state = tcp->tcp_state;
-			(void) snmp_append_data2(mp6_conn_data, &mp6_conn_tail,
-			    (char *)&tce6, sizeof (tce6));
+
+			(void) snmp_append_data2(mp6_conn_ctl->b_cont,
+			    &mp6_conn_tail, (char *)&tce6, sizeof (tce6));
+
+			mlp.tme_connidx = v6_conn_idx++;
+			if (needattr)
+				(void) snmp_append_data2(mp6_attr_ctl->b_cont,
+				    &mp6_attr_tail, (char *)&mlp, sizeof (mlp));
 			}
 			/*
 			 * Create an IPv4 table entry for IPv4 entries and also
@@ -15747,8 +15918,16 @@
 				tce.tcpConnEntryInfo.ce_mss =  tcp->tcp_mss;
 				tce.tcpConnEntryInfo.ce_state =
 				    tcp->tcp_state;
-				(void) snmp_append_data2(mp_conn_data,
+
+				(void) snmp_append_data2(mp_conn_ctl->b_cont,
 				    &mp_conn_tail, (char *)&tce, sizeof (tce));
+
+				mlp.tme_connidx = v4_conn_idx++;
+				if (needattr)
+					(void) snmp_append_data2(
+					    mp_attr_ctl->b_cont,
+					    &mp_attr_tail, (char *)&mlp,
+					    sizeof (mlp));
 			}
 		}
 	}
@@ -15768,16 +15947,38 @@
 	    sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_TCP;
 	optp->name = MIB2_TCP_CONN;
-	optp->len = msgdsize(mp_conn_data);
+	optp->len = msgdsize(mp_conn_ctl->b_cont);
 	qreply(q, mp_conn_ctl);
 
+	/* table of MLP attributes... */
+	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_TCP;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp_attr_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp_attr_ctl);
+	else
+		qreply(q, mp_attr_ctl);
+
 	/* table of IPv6 connections... */
 	optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
 	    sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_TCP6;
 	optp->name = MIB2_TCP6_CONN;
-	optp->len = msgdsize(mp6_conn_data);
+	optp->len = msgdsize(mp6_conn_ctl->b_cont);
 	qreply(q, mp6_conn_ctl);
+
+	/* table of IPv6 MLP attributes... */
+	optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_TCP6;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp6_attr_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp6_attr_ctl);
+	else
+		qreply(q, mp6_attr_ctl);
 	return (1);
 }
 
@@ -16633,11 +16834,16 @@
  * but instead the code relies on:
  * - the fact that the address of the array and its size never changes
  * - the atomic assignment of the elements of the array
+ *
+ * Returns 0 if there are no more ports available.
+ *
+ * TS note: skip multilevel ports.
  */
 static in_port_t
-tcp_update_next_port(in_port_t port, boolean_t random)
+tcp_update_next_port(in_port_t port, const tcp_t *tcp, boolean_t random)
 {
 	int i;
+	boolean_t restart = B_FALSE;
 
 	if (random && tcp_random_anon_port != 0) {
 		(void) random_get_pseudo_bytes((uint8_t *)&port,
@@ -16659,9 +16865,16 @@
 	}
 
 retry:
-	if (port < tcp_smallest_anon_port || port > tcp_largest_anon_port)
+	if (port < tcp_smallest_anon_port)
 		port = (in_port_t)tcp_smallest_anon_port;
 
+	if (port > tcp_largest_anon_port) {
+		if (restart)
+			return (0);
+		restart = B_TRUE;
+		port = (in_port_t)tcp_smallest_anon_port;
+	}
+
 	if (port < tcp_smallest_nonpriv_port)
 		port = (in_port_t)tcp_smallest_nonpriv_port;
 
@@ -16671,30 +16884,47 @@
 			/*
 			 * Make sure whether the port is in the
 			 * valid range.
-			 *
-			 * XXX Note that if tcp_g_epriv_ports contains
-			 * all the anonymous ports this will be an
-			 * infinite loop.
 			 */
 			goto retry;
 		}
 	}
+	if (is_system_labeled() &&
+	    (i = tsol_next_port(crgetzone(tcp->tcp_cred), port,
+	    IPPROTO_TCP, B_TRUE)) != 0) {
+		port = i;
+		goto retry;
+	}
 	return (port);
 }
 
 /*
- * Return the next anonymous port in the priviledged port range for
+ * Return the next anonymous port in the privileged port range for
  * bind checking.  It starts at IPPORT_RESERVED - 1 and goes
  * downwards.  This is the same behavior as documented in the userland
  * library call rresvport(3N).
+ *
+ * TS note: skip multilevel ports.
  */
 static in_port_t
-tcp_get_next_priv_port(void)
+tcp_get_next_priv_port(const tcp_t *tcp)
 {
 	static in_port_t next_priv_port = IPPORT_RESERVED - 1;
-
-	if (next_priv_port < tcp_min_anonpriv_port) {
+	in_port_t nextport;
+	boolean_t restart = B_FALSE;
+
+retry:
+	if (next_priv_port < tcp_min_anonpriv_port ||
+	    next_priv_port >= IPPORT_RESERVED) {
 		next_priv_port = IPPORT_RESERVED - 1;
+		if (restart)
+			return (0);
+		restart = B_TRUE;
+	}
+	if (is_system_labeled() &&
+	    (nextport = tsol_next_port(crgetzone(tcp->tcp_cred),
+	    next_priv_port, IPPROTO_TCP, B_FALSE)) != 0) {
+		next_priv_port = nextport;
+		goto retry;
 	}
 	return (next_priv_port--);
 }
@@ -17435,9 +17665,6 @@
 		q->q_qinfo = &tcp_winit;
 		listener = eager->tcp_listener;
 		eager->tcp_issocket = B_TRUE;
-		eager->tcp_cred = econnp->conn_cred =
-		    listener->tcp_connp->conn_cred;
-		crhold(econnp->conn_cred);
 		econnp->conn_zoneid = listener->tcp_connp->conn_zoneid;
 
 		/* Put the ref for IP */
@@ -17660,8 +17887,7 @@
 			return;
 		}
 		if (type == T_SVR4_OPTMGMT_REQ) {
-			cred_t	*cr = DB_CREDDEF(mp,
-			    tcp->tcp_cred);
+			cred_t	*cr = DB_CREDDEF(mp, tcp->tcp_cred);
 			if (snmpcom_req(q, mp, tcp_snmp_set, tcp_snmp_get,
 			    cr)) {
 				/*
@@ -17945,12 +18171,15 @@
 
 	ASSERT(DB_TYPE(mp) == M_DATA);
 
+	mblk_setcred(mp, CONN_CRED(connp));
+
 	ipha = (ipha_t *)mp->b_rptr;
 	src = ipha->ipha_src;
 	dst = ipha->ipha_dst;
 
 	/*
-	 * Drop off slow path for IPv6 and also if options are present.
+	 * Drop off fast path for IPv6 and also if options are present or
+	 * we need to resolve a TS label.
 	 */
 	if (tcp->tcp_ipversion != IPV4_VERSION ||
 	    !IPCL_IS_CONNECTED(connp) ||
@@ -17959,6 +18188,7 @@
 	    connp->conn_nexthop_set ||
 	    connp->conn_xmit_if_ill != NULL ||
 	    connp->conn_nofailover_ill != NULL ||
+	    !connp->conn_ulp_labeled ||
 	    ipha->ipha_ident == IP_HDR_INCLUDED ||
 	    ipha->ipha_version_and_hdr_length != IP_SIMPLE_HDR_VERSION ||
 	    IPP_ENABLED(IPP_LOCAL_OUT)) {
@@ -17987,7 +18217,8 @@
 		mutex_exit(&connp->conn_lock);
 		if (ire != NULL)
 			IRE_REFRELE_NOTR(ire);
-		ire = ire_cache_lookup(dst, connp->conn_zoneid);
+		ire = ire_cache_lookup(dst, connp->conn_zoneid,
+		    MBLK_GETLABEL(mp));
 		if (ire == NULL) {
 			if (tcp->tcp_snd_zcopy_aware)
 				mp = tcp_zcopy_backoff(tcp, mp, 0);
@@ -18018,6 +18249,12 @@
 		 */
 		if (!cached)
 			IRE_REFRELE_NOTR(ire);
+
+		/*
+		 * Rampart note: no need to select a new label here, since
+		 * labels are not allowed to change during the life of a TCP
+		 * connection.
+		 */
 	}
 
 	if (ire->ire_flags & RTF_MULTIRT ||
@@ -18759,6 +18996,7 @@
 	ill_zerocopy_capab_t *zc_cap = NULL;
 	uint16_t	*up;
 	int		err;
+	conn_t		*connp;
 
 #ifdef	_BIG_ENDIAN
 #define	IPVER(ip6h)	((((uint32_t *)ip6h)[0] >> 28) & 0x7)
@@ -18795,9 +19033,11 @@
 	    tcp->tcp_ip_hdr_len == IP_SIMPLE_HDR_LENGTH) ||
 	    (tcp->tcp_ipversion == IPV6_VERSION &&
 	    tcp->tcp_ip_hdr_len == IPV6_HDR_LEN));
-	ASSERT(tcp->tcp_connp != NULL);
-	ASSERT(CONN_IS_MD_FASTPATH(tcp->tcp_connp));
-	ASSERT(!CONN_IPSEC_OUT_ENCAPSULATED(tcp->tcp_connp));
+
+	connp = tcp->tcp_connp;
+	ASSERT(connp != NULL);
+	ASSERT(CONN_IS_MD_FASTPATH(connp));
+	ASSERT(!CONN_IPSEC_OUT_ENCAPSULATED(connp));
 
 	/*
 	 * Note that tcp will only declare at most 2 payload spans per
@@ -18828,33 +19068,35 @@
 	 * in proceeding any further, and we should just hand everything
 	 * off to the legacy path.
 	 */
-	mutex_enter(&tcp->tcp_connp->conn_lock);
-	ire = tcp->tcp_connp->conn_ire_cache;
-	ASSERT(!(tcp->tcp_connp->conn_state_flags & CONN_INCIPIENT));
+	mutex_enter(&connp->conn_lock);
+	ire = connp->conn_ire_cache;
+	ASSERT(!(connp->conn_state_flags & CONN_INCIPIENT));
 	if (ire != NULL && ((af == AF_INET && ire->ire_addr == dst) ||
 	    (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(&ire->ire_addr_v6,
 	    &tcp->tcp_ip6h->ip6_dst))) &&
 	    !(ire->ire_marks & IRE_MARK_CONDEMNED)) {
 		IRE_REFHOLD(ire);
-		mutex_exit(&tcp->tcp_connp->conn_lock);
+		mutex_exit(&connp->conn_lock);
 	} else {
 		boolean_t cached = B_FALSE;
+		ts_label_t *tsl;
 
 		/* force a recheck later on */
 		tcp->tcp_ire_ill_check_done = B_FALSE;
 
 		TCP_DBGSTAT(tcp_ire_null1);
-		tcp->tcp_connp->conn_ire_cache = NULL;
-		mutex_exit(&tcp->tcp_connp->conn_lock);
+		connp->conn_ire_cache = NULL;
+		mutex_exit(&connp->conn_lock);
 
 		/* Release the old ire */
 		if (ire != NULL)
 			IRE_REFRELE_NOTR(ire);
 
+		tsl = crgetlabel(CONN_CRED(connp));
 		ire = (af == AF_INET) ?
-		    ire_cache_lookup(dst, tcp->tcp_connp->conn_zoneid) :
+		    ire_cache_lookup(dst, connp->conn_zoneid, tsl) :
 		    ire_cache_lookup_v6(&tcp->tcp_ip6h->ip6_dst,
-		    tcp->tcp_connp->conn_zoneid);
+		    connp->conn_zoneid, tsl);
 
 		if (ire == NULL) {
 			TCP_STAT(tcp_ire_null);
@@ -18869,10 +19111,10 @@
 		 * unplumb thread has not yet started cleaning up the conns.
 		 * Hence we don't need to grab the conn lock.
 		 */
-		if (!(tcp->tcp_connp->conn_state_flags & CONN_CLOSING)) {
+		if (!(connp->conn_state_flags & CONN_CLOSING)) {
 			rw_enter(&ire->ire_bucket->irb_lock, RW_READER);
 			if (!(ire->ire_marks & IRE_MARK_CONDEMNED)) {
-				tcp->tcp_connp->conn_ire_cache = ire;
+				connp->conn_ire_cache = ire;
 				cached = B_TRUE;
 			}
 			rw_exit(&ire->ire_bucket->irb_lock);
@@ -18917,7 +19159,7 @@
 		TCP_STAT(tcp_mdt_conn_halted2);
 		tcp->tcp_mdt = B_FALSE;
 		ip1dbg(("tcp_multisend: disabling MDT for connp %p on "
-		    "interface %s\n", (void *)tcp->tcp_connp, ill->ill_name));
+		    "interface %s\n", (void *)connp, ill->ill_name));
 		/* IRE will be released prior to returning */
 		goto legacy_send_no_md;
 	}
@@ -21129,6 +21371,7 @@
 	void		*addr;
 	queue_t		*q = tcp_g_q;
 	tcp_t		*tcp = Q_TO_TCP(q);
+	cred_t		*cr;
 
 	if (!tcp_send_rst_chk()) {
 		tcp_rst_unsent++;
@@ -21253,6 +21496,35 @@
 		BUMP_MIB(&tcp_mib, tcpOutRsts);
 		BUMP_MIB(&tcp_mib, tcpOutControl);
 	}
+
+	/* IP trusts us to set up labels when required. */
+	if (is_system_labeled() && (cr = DB_CRED(mp)) != NULL &&
+	    crgetlabel(cr) != NULL) {
+		int err, adjust;
+
+		if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION)
+			err = tsol_check_label(cr, &mp, &adjust,
+			    tcp->tcp_connp->conn_mac_exempt);
+		else
+			err = tsol_check_label_v6(cr, &mp, &adjust,
+			    tcp->tcp_connp->conn_mac_exempt);
+		if (mctl_present)
+			ipsec_mp->b_cont = mp;
+		else
+			ipsec_mp = mp;
+		if (err != 0) {
+			freemsg(ipsec_mp);
+			return;
+		}
+		if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+			ipha = (ipha_t *)mp->b_rptr;
+			adjust += ntohs(ipha->ipha_length);
+			ipha->ipha_length = htons(adjust);
+		} else {
+			ip6h = (ip6_t *)mp->b_rptr;
+		}
+	}
+
 	if (mctl_present) {
 		ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
 
@@ -21263,9 +21535,15 @@
 	}
 	/*
 	 * NOTE:  one might consider tracing a TCP packet here, but
-	 * this function has no active TCP state nd no tcp structure
-	 * which has trace buffer.  If we traced here, we would have
+	 * this function has no active TCP state and no tcp structure
+	 * that has a trace buffer.  If we traced here, we would have
 	 * to keep a local trace buffer in tcp_record_trace().
+	 *
+	 * TSol note: The mblk that contains the incoming packet was
+	 * reused by tcp_xmit_listener_reset, so it already contains
+	 * the right credentials and we don't need to call mblk_setcred.
+	 * Also the conn's cred is not right since it is associated
+	 * with tcp_g_q.
 	 */
 	CALL_IP_WPUT(tcp->tcp_connp, tcp->tcp_wq, ipsec_mp);
 
@@ -21452,7 +21730,15 @@
 		if (ipsec_mp == NULL)
 			return;
 	}
-
+	if (is_system_labeled() && !tsol_can_reply_error(mp)) {
+		DTRACE_PROBE2(
+		    tx__ip__log__error__nolistener__tcp,
+		    char *, "Could not reply with RST to mp(1)",
+		    mblk_t *, mp);
+		ip2dbg(("tcp_xmit_listeners_reset: not permitted to reply\n"));
+		freemsg(ipsec_mp);
+		return;
+	}
 
 	rptr = mp->b_rptr;
 
@@ -24271,77 +24557,6 @@
 }
 
 /*
- * Return zero if the buffers are identical in length and content.
- * This is used for comparing extension header buffers.
- * Note that an extension header would be declared different
- * even if all that changed was the next header value in that header i.e.
- * what really changed is the next extension header.
- */
-static boolean_t
-tcp_cmpbuf(void *a, uint_t alen, boolean_t b_valid, void *b, uint_t blen)
-{
-	if (!b_valid)
-		blen = 0;
-
-	if (alen != blen)
-		return (B_TRUE);
-	if (alen == 0)
-		return (B_FALSE);	/* Both zero length */
-	return (bcmp(a, b, alen));
-}
-
-/*
- * Preallocate memory for tcp_savebuf(). Returns B_TRUE if ok.
- * Return B_FALSE if memory allocation fails - don't change any state!
- */
-static boolean_t
-tcp_allocbuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
-    void *src, uint_t srclen)
-{
-	void *dst;
-
-	if (!src_valid)
-		srclen = 0;
-
-	ASSERT(*dstlenp == 0);
-	if (src != NULL && srclen != 0) {
-		dst = mi_alloc(srclen, BPRI_MED);
-		if (dst == NULL)
-			return (B_FALSE);
-	} else {
-		dst = NULL;
-	}
-	if (*dstp != NULL) {
-		mi_free(*dstp);
-		*dstp = NULL;
-		*dstlenp = 0;
-	}
-	*dstp = dst;
-	if (dst != NULL)
-		*dstlenp = srclen;
-	else
-		*dstlenp = 0;
-	return (B_TRUE);
-}
-
-/*
- * Replace what is in *dst, *dstlen with the source.
- * Assumes tcp_allocbuf has already been called.
- */
-static void
-tcp_savebuf(void **dstp, uint_t *dstlenp, boolean_t src_valid,
-    void *src, uint_t srclen)
-{
-	if (!src_valid)
-		srclen = 0;
-
-	ASSERT(*dstlenp == srclen);
-	if (src != NULL && srclen != 0) {
-		bcopy(src, *dstp, srclen);
-	}
-}
-
-/*
  * Allocate a T_SVR4_OPTMGMT_REQ.
  * The caller needs to increment tcp_drop_opt_ack_cnt when sending these so
  * that tcp_rput_other can drop the acks.
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,7 +39,6 @@
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
-#include <netinet/ip_mroute.h>
 #include <inet/optcom.h>
 
 
@@ -76,6 +74,10 @@
 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0
 	},
 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+{ SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
 { TCP_NODELAY,	IPPROTO_TCP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0
 	},
 { TCP_MAXSEG,	IPPROTO_TCP, OA_R, OA_R, OP_NP, OP_PASSNEXT, sizeof (uint_t),
--- a/usr/src/uts/common/inet/udp/udp.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/udp/udp.c	Fri Mar 24 12:29:20 2006 -0800
@@ -39,7 +39,6 @@
 #define	_SUN_TPI_VERSION 2
 #include <sys/tihdr.h>
 #include <sys/timod.h>
-#include <sys/tiuser.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/strsubr.h>
@@ -85,11 +84,15 @@
 /*
  * The ipsec_info.h header file is here since it has the definition for the
  * M_CTL message types used by IP to convey information to the ULP. The
- * ipsec_info.h needs the pfkeyv2.h, hence the latters presence.
+ * ipsec_info.h needs the pfkeyv2.h, hence the latter's presence.
  */
 #include <net/pfkeyv2.h>
 #include <inet/ipsec_info.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+#include <rpc/pmap_prot.h>
+
 /*
  * Synchronization notes:
  *
@@ -249,17 +252,24 @@
 
 /*
  * This controls the rate some ndd info report functions can be used
- * by non-priviledged users.  It stores the last time such info is
+ * by non-privileged users.  It stores the last time such info is
  * requested.  When those report functions are called again, this
  * is checked with the current time and compare with the ndd param
  * udp_ndd_get_info_interval.
  */
 static clock_t udp_last_ndd_get_info_time;
 #define	NDD_TOO_QUICK_MSG \
-	"ndd get info rate too high for non-priviledged users, try again " \
+	"ndd get info rate too high for non-privileged users, try again " \
 	"later.\n"
 #define	NDD_OUT_OF_BUF_MSG	"<< Out of buffer >>\n"
 
+/* Option processing attrs */
+typedef struct udpattrs_s {
+	ip6_pkt_t	*udpattr_ipp;
+	mblk_t		*udpattr_mb;
+	boolean_t	udpattr_credset;
+} udpattrs_t;
+
 static void	udp_addr_req(queue_t *q, mblk_t *mp);
 static void	udp_bind(queue_t *q, mblk_t *mp);
 static void	udp_bind_hash_insert(udp_fanout_t *uf, udp_t *udp);
@@ -287,14 +297,12 @@
 static int	udp_open(queue_t *q, dev_t *devp, int flag, int sflag,
 		    cred_t *credp);
 static  int	udp_unitdata_opt_process(queue_t *q, mblk_t *mp,
-		    int *errorp, void *thisdg_attrs);
+		    int *errorp, udpattrs_t *udpattrs);
 static boolean_t udp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name);
 static int	udp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
 static boolean_t udp_param_register(udpparam_t *udppa, int cnt);
 static int	udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
 		    cred_t *cr);
-static int	udp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky,
-		    uchar_t **optbufp, uint_t *optlenp);
 static void	udp_report_item(mblk_t *mp, udp_t *udp);
 static void	udp_rput(queue_t *q, mblk_t *mp);
 static void	udp_rput_other(queue_t *, mblk_t *);
@@ -307,12 +315,13 @@
 static void	udp_ud_err(queue_t *q, mblk_t *mp, uchar_t *destaddr,
 		    t_scalar_t destlen, t_scalar_t err);
 static void	udp_unbind(queue_t *q, mblk_t *mp);
-static in_port_t udp_update_next_port(in_port_t port, boolean_t random);
+static in_port_t udp_update_next_port(udp_t *udp, in_port_t port,
+    boolean_t random);
 static void	udp_wput(queue_t *q, mblk_t *mp);
 static mblk_t	*udp_output_v4(conn_t *, mblk_t *mp, ipaddr_t v4dst,
 		    uint16_t port, uint_t srcid, int *error);
 static mblk_t	*udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6,
-		    t_scalar_t tudr_optlen, int *error);
+		    int *error);
 static void	udp_wput_other(queue_t *q, mblk_t *mp);
 static void	udp_wput_iocdata(queue_t *q, mblk_t *mp);
 static void	udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr,
@@ -459,7 +468,7 @@
 /* END CSTYLED */
 
 /*
- * The smallest anonymous port in the priviledged port range which UDP
+ * The smallest anonymous port in the privileged port range which UDP
  * looks for free port.  Use in the option UDP_ANONPRIVBIND.
  */
 static in_port_t udp_min_anonpriv_port = 512;
@@ -903,17 +912,38 @@
 }
 
 /*
- * Return the next anonymous port in the priviledged port range for
+ * Return the next anonymous port in the privileged port range for
  * bind checking.
+ *
+ * Trusted Extension (TX) notes: TX allows administrator to mark or
+ * reserve ports as Multilevel ports (MLP). MLP has special function
+ * on TX systems. Once a port is made MLP, it's not available as
+ * ordinary port. This creates "holes" in the port name space. It
+ * may be necessary to skip the "holes" find a suitable anon port.
  */
 static in_port_t
-udp_get_next_priv_port(void)
+udp_get_next_priv_port(udp_t *udp)
 {
 	static in_port_t next_priv_port = IPPORT_RESERVED - 1;
-
-	if (next_priv_port < udp_min_anonpriv_port) {
+	in_port_t nextport;
+	boolean_t restart = B_FALSE;
+
+retry:
+	if (next_priv_port < udp_min_anonpriv_port ||
+	    next_priv_port >= IPPORT_RESERVED) {
 		next_priv_port = IPPORT_RESERVED - 1;
-	}
+		if (restart)
+			return (0);
+		restart = B_TRUE;
+	}
+
+	if (is_system_labeled() &&
+	    (nextport = tsol_next_port(crgetzone(udp->udp_connp->conn_cred),
+	    next_priv_port, IPPROTO_UDP, B_FALSE)) != 0) {
+		next_priv_port = nextport;
+		goto retry;
+	}
+
 	return (next_priv_port--);
 }
 
@@ -1098,6 +1128,8 @@
 	zoneid_t	zoneid;
 	conn_t		*connp;
 	udp_t		*udp;
+	boolean_t	is_inaddr_any;
+	mlp_type_t	addrtype, mlptype;
 
 	connp = Q_TO_CONN(q);
 	udp = connp->conn_udp;
@@ -1198,10 +1230,10 @@
 		 * valid range.
 		 */
 		if (udp->udp_anon_priv_bind) {
-			port = udp_get_next_priv_port();
+			port = udp_get_next_priv_port(udp);
 		} else {
-			port = udp_update_next_port(udp_g_next_port_to_try,
-			    B_TRUE);
+			port = udp_update_next_port(udp,
+			    udp_g_next_port_to_try, B_TRUE);
 		}
 	} else {
 		/*
@@ -1232,6 +1264,11 @@
 		}
 	}
 
+	if (port == 0) {
+		udp_err_ack(q, mp, TNOADDR, 0);
+		return;
+	}
+
 	/*
 	 * Copy the source address into our udp structure. This address
 	 * may still be zero; if so, IP will fill in the correct address
@@ -1286,13 +1323,13 @@
 		loopmax = udp_largest_anon_port - udp_smallest_anon_port + 1;
 	}
 
+	is_inaddr_any = V6_OR_V4_INADDR_ANY(v6src);
 	zoneid = connp->conn_zoneid;
+
 	for (;;) {
 		udp_t		*udp1;
-		boolean_t	is_inaddr_any;
 		boolean_t	found_exclbind = B_FALSE;
 
-		is_inaddr_any = V6_OR_V4_INADDR_ANY(v6src);
 		/*
 		 * Walk through the list of udp streams bound to
 		 * requested port with the same IP address.
@@ -1302,8 +1339,17 @@
 		mutex_enter(&udpf->uf_lock);
 		for (udp1 = udpf->uf_udp; udp1 != NULL;
 		    udp1 = udp1->udp_bind_hash) {
-			if (lport != udp1->udp_port ||
-			    zoneid != udp1->udp_connp->conn_zoneid)
+			if (lport != udp1->udp_port)
+				continue;
+
+			/*
+			 * On a labeled system, we must treat bindings to ports
+			 * on shared IP addresses by sockets with MAC exemption
+			 * privilege as being in all zones, as there's
+			 * otherwise no way to identify the right receiver.
+			 */
+			if (zoneid != udp1->udp_connp->conn_zoneid &&
+			    !udp->udp_mac_exempt && !udp1->udp_mac_exempt)
 				continue;
 
 			/*
@@ -1321,8 +1367,12 @@
 			 * unspec	spec		no
 			 * spec		unspec		no
 			 * spec		spec		yes if A
+			 *
+			 * For labeled systems, SO_MAC_EXEMPT behaves the same
+			 * as UDP_EXCLBIND, except that zoneid is ignored.
 			 */
-			if (udp1->udp_exclbind || udp->udp_exclbind) {
+			if (udp1->udp_exclbind || udp->udp_exclbind ||
+			    udp1->udp_mac_exempt || udp->udp_mac_exempt) {
 				if (V6_OR_V4_INADDR_ANY(
 				    udp1->udp_bound_v6src) ||
 				    is_inaddr_any ||
@@ -1388,7 +1438,7 @@
 		}
 
 		if (udp->udp_anon_priv_bind) {
-			port = udp_get_next_priv_port();
+			port = udp_get_next_priv_port(udp);
 		} else {
 			if ((count == 0) && (requested_port != 0)) {
 				/*
@@ -1397,15 +1447,16 @@
 				 * requested_port to 0, so that we will
 				 * update udp_g_next_port_to_try below.
 				 */
-				port = udp_update_next_port(
+				port = udp_update_next_port(udp,
 				    udp_g_next_port_to_try, B_TRUE);
 				requested_port = 0;
 			} else {
-				port = udp_update_next_port(port + 1, B_FALSE);
+				port = udp_update_next_port(udp, port + 1,
+				    B_FALSE);
 			}
 		}
 
-		if (++count >= loopmax) {
+		if (port == 0 || ++count >= loopmax) {
 			/*
 			 * We've tried every possible port number and
 			 * there are none available, so send an error
@@ -1468,6 +1519,88 @@
 
 	}
 
+	connp->conn_anon_port = (is_system_labeled() && requested_port == 0);
+	if (is_system_labeled() && (!connp->conn_anon_port ||
+	    connp->conn_anon_mlp)) {
+		uint16_t mlpport;
+		cred_t *cr = connp->conn_cred;
+		zone_t *zone;
+
+		connp->conn_mlp_type = udp->udp_recvucred ? mlptBoth :
+		    mlptSingle;
+		addrtype = tsol_mlp_addr_type(zoneid, IPV6_VERSION, &v6src);
+		if (addrtype == mlptSingle) {
+			udp_err_ack(q, mp, TNOADDR, 0);
+			connp->conn_anon_port = B_FALSE;
+			connp->conn_mlp_type = mlptSingle;
+			return;
+		}
+		mlpport = connp->conn_anon_port ? PMAPPORT : port;
+		zone = crgetzone(cr);
+		mlptype = tsol_mlp_port_type(zone, IPPROTO_UDP, mlpport,
+		    addrtype);
+		if (mlptype != mlptSingle &&
+		    (connp->conn_mlp_type == mlptSingle ||
+		    secpolicy_net_bindmlp(cr) != 0)) {
+			if (udp->udp_debug) {
+				(void) strlog(UDP_MOD_ID, 0, 1,
+				    SL_ERROR|SL_TRACE,
+				    "udp_bind: no priv for multilevel port %d",
+				    mlpport);
+			}
+			udp_err_ack(q, mp, TACCES, 0);
+			connp->conn_anon_port = B_FALSE;
+			connp->conn_mlp_type = mlptSingle;
+			return;
+		}
+
+		/*
+		 * If we're specifically binding a shared IP address and the
+		 * port is MLP on shared addresses, then check to see if this
+		 * zone actually owns the MLP.  Reject if not.
+		 */
+		if (mlptype == mlptShared && addrtype == mlptShared) {
+			zoneid_t mlpzone;
+
+			mlpzone = tsol_mlp_findzone(IPPROTO_UDP,
+			    htons(mlpport));
+			if (connp->conn_zoneid != mlpzone) {
+				if (udp->udp_debug) {
+					(void) strlog(UDP_MOD_ID, 0, 1,
+					    SL_ERROR|SL_TRACE,
+					    "udp_bind: attempt to bind port "
+					    "%d on shared addr in zone %d "
+					    "(should be %d)",
+					    mlpport, connp->conn_zoneid,
+					    mlpzone);
+				}
+				udp_err_ack(q, mp, TACCES, 0);
+				connp->conn_anon_port = B_FALSE;
+				connp->conn_mlp_type = mlptSingle;
+				return;
+			}
+		}
+		if (connp->conn_anon_port) {
+			int error;
+
+			error = tsol_mlp_anon(zone, mlptype, connp->conn_ulp,
+			    port, B_TRUE);
+			if (error != 0) {
+				if (udp->udp_debug) {
+					(void) strlog(UDP_MOD_ID, 0, 1,
+					    SL_ERROR|SL_TRACE,
+					    "udp_bind: cannot establish anon "
+					    "MLP for port %d", port);
+				}
+				udp_err_ack(q, mp, TACCES, 0);
+				connp->conn_anon_port = B_FALSE;
+				connp->conn_mlp_type = mlptSingle;
+				return;
+			}
+		}
+		connp->conn_mlp_type = mlptype;
+	}
+
 	/* Pass the protocol number in the message following the address. */
 	*mp->b_wptr++ = IPPROTO_UDP;
 	if (!V6_OR_V4_INADDR_ANY(udp->udp_v6src)) {
@@ -1769,6 +1902,7 @@
 	linkb(mp1, mp);
 	linkb(mp1, mp2);
 
+	mblk_setcred(mp1, udp->udp_connp->conn_cred);
 	if (udp->udp_family == AF_INET)
 		mp1 = ip_bind_v4(q, mp1, udp->udp_connp);
 	else
@@ -1819,6 +1953,7 @@
 	connp->conn_flags &= ~IPCL_UDP;
 	connp->conn_state_flags &=
 	    ~(CONN_CLOSING | CONN_CONDEMNED | CONN_QUIESCED);
+	connp->conn_ulp_labeled = B_FALSE;
 	return (0);
 }
 
@@ -1879,28 +2014,7 @@
 		udp->udp_sticky_hdrs_len = 0;
 	}
 
-	if (udp->udp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) {
-		kmem_free(udp->udp_sticky_ipp.ipp_hopopts,
-		    udp->udp_sticky_ipp.ipp_hopoptslen);
-		udp->udp_sticky_ipp.ipp_hopopts = NULL;
-	}
-	if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) {
-		kmem_free(udp->udp_sticky_ipp.ipp_rtdstopts,
-		    udp->udp_sticky_ipp.ipp_rtdstoptslen);
-		udp->udp_sticky_ipp.ipp_rtdstopts = NULL;
-	}
-	if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTHDR) {
-		kmem_free(udp->udp_sticky_ipp.ipp_rthdr,
-		    udp->udp_sticky_ipp.ipp_rthdrlen);
-		udp->udp_sticky_ipp.ipp_rthdr = NULL;
-	}
-	if (udp->udp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) {
-		kmem_free(udp->udp_sticky_ipp.ipp_dstopts,
-		    udp->udp_sticky_ipp.ipp_dstoptslen);
-		udp->udp_sticky_ipp.ipp_dstopts = NULL;
-	}
-	udp->udp_sticky_ipp.ipp_fields &=
-	    ~(IPPF_HOPOPTS|IPPF_RTDSTOPTS|IPPF_RTHDR|IPPF_DSTOPTS);
+	ip6_pkt_free(&udp->udp_sticky_ipp);
 
 	udp->udp_connp = NULL;
 	connp->conn_udp = NULL;
@@ -2835,10 +2949,20 @@
 	connp->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
 	connp->conn_zoneid = zoneid;
 
+	/*
+	 * If the caller has the process-wide flag set, then default to MAC
+	 * exempt mode.  This allows read-down to unlabeled hosts.
+	 */
+	if (getpflags(NET_MAC_AWARE, credp) != 0)
+		udp->udp_mac_exempt = B_TRUE;
+
 	if (connp->conn_flags & IPCL_SOCKET) {
 		udp->udp_issocket = B_TRUE;
 		udp->udp_direct_sockfs = B_TRUE;
 	}
+
+	connp->conn_ulp_labeled = is_system_labeled();
+
 	mutex_exit(&connp->conn_lock);
 
 	/*
@@ -2853,6 +2977,7 @@
 	if (udp->udp_family == AF_INET6) {
 		/* Build initial header template for transmit */
 		if ((err = udp_build_hdrs(q, udp)) != 0) {
+error:
 			qprocsoff(UDP_RD(q));
 			udp->udp_connp = NULL;
 			connp->conn_udp = NULL;
@@ -2931,6 +3056,7 @@
 	conn_t	*connp;
 	udp_t	*udp;
 	ip6_pkt_t *ipp;
+	int	len;
 
 	q = UDP_WR(q);
 	connp = Q_TO_CONN(q);
@@ -2979,6 +3105,12 @@
 		case SO_TIMESTAMP:
 			*i1 = udp->udp_timestamp;
 			break;
+		case SO_ANON_MLP:
+			*i1 = udp->udp_anon_mlp;
+			break;	/* goto sizeof (int) option return */
+		case SO_MAC_EXEMPT:
+			*i1 = udp->udp_mac_exempt;
+			break;	/* goto sizeof (int) option return */
 		default:
 			return (-1);
 		}
@@ -2989,10 +3121,12 @@
 		switch (name) {
 		case IP_OPTIONS:
 		case T_IP_OPTIONS:
-			if (udp->udp_ip_rcv_options_len)
-				bcopy(udp->udp_ip_rcv_options, ptr,
-				    udp->udp_ip_rcv_options_len);
-			return (udp->udp_ip_rcv_options_len);
+			len = udp->udp_ip_rcv_options_len - udp->udp_label_len;
+			if (len > 0) {
+				bcopy(udp->udp_ip_rcv_options +
+				    udp->udp_label_len, ptr, len);
+			}
+			return (len);
 		case IP_TOS:
 		case T_IP_TOS:
 			*i1 = (int)udp->udp_type_of_service;
@@ -3153,8 +3287,21 @@
 		case IPV6_HOPOPTS:
 			if (!(ipp->ipp_fields & IPPF_HOPOPTS))
 				return (0);
-			bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen);
-			return (ipp->ipp_hopoptslen);
+			if (ipp->ipp_hopoptslen <= udp->udp_label_len_v6)
+				return (0);
+			/*
+			 * The cipso/label option is added by kernel.
+			 * User is not usually aware of this option.
+			 * We copy out the hbh opt after the label option.
+			 */
+			bcopy((char *)ipp->ipp_hopopts + udp->udp_label_len_v6,
+			    ptr, ipp->ipp_hopoptslen - udp->udp_label_len_v6);
+			if (udp->udp_label_len_v6 > 0) {
+				ptr[0] = ((char *)ipp->ipp_hopopts)[0];
+				ptr[1] = (ipp->ipp_hopoptslen -
+				    udp->udp_label_len_v6 + 7) / 8 - 1;
+			}
+			return (ipp->ipp_hopoptslen - udp->udp_label_len_v6);
 		case IPV6_RTHDRDSTOPTS:
 			if (!(ipp->ipp_fields & IPPF_RTDSTOPTS))
 				return (0);
@@ -3208,12 +3355,14 @@
     int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
     uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
 {
+	udpattrs_t *attrs = thisdg_attrs;
 	int	*i1 = (int *)invalp;
 	boolean_t onoff = (*i1 == 0) ? 0 : 1;
 	boolean_t checkonly;
 	int	error;
 	conn_t	*connp;
 	udp_t	*udp;
+	uint_t	newlen;
 
 	q = UDP_WR(q);
 	connp = Q_TO_CONN(q);
@@ -3332,6 +3481,55 @@
 			if (!checkonly)
 				udp->udp_timestamp = onoff;
 			break;
+		case SO_ANON_MLP:
+			if (!checkonly)
+				udp->udp_anon_mlp = onoff;
+			break;
+		case SO_MAC_EXEMPT:
+			if (secpolicy_net_mac_aware(cr) != 0 ||
+			    udp->udp_state != TS_UNBND)
+				return (EACCES);
+			if (!checkonly)
+				udp->udp_mac_exempt = onoff;
+			break;
+		case SCM_UCRED: {
+			struct ucred_s *ucr;
+			cred_t *cr, *newcr;
+			ts_label_t *tsl;
+
+			/*
+			 * Only sockets that have proper privileges and are
+			 * bound to MLPs will have any other value here, so
+			 * this implicitly tests for privilege to set label.
+			 */
+			if (connp->conn_mlp_type == mlptSingle)
+				break;
+			ucr = (struct ucred_s *)invalp;
+			if (inlen != ucredsize ||
+			    ucr->uc_labeloff < sizeof (*ucr) ||
+			    ucr->uc_labeloff + sizeof (bslabel_t) > inlen)
+				return (EINVAL);
+			if (!checkonly) {
+				mblk_t *mb;
+
+				if (attrs == NULL ||
+				    (mb = attrs->udpattr_mb) == NULL)
+					return (EINVAL);
+				if ((cr = DB_CRED(mb)) == NULL)
+					cr = udp->udp_connp->conn_cred;
+				ASSERT(cr != NULL);
+				if ((tsl = crgetlabel(cr)) == NULL)
+					return (EINVAL);
+				newcr = copycred_from_bslabel(cr, UCLABEL(ucr),
+				    tsl->tsl_doi, KM_NOSLEEP);
+				if (newcr == NULL)
+					return (ENOSR);
+				mblk_setcred(mb, newcr);
+				attrs->udpattr_credset = B_TRUE;
+				crfree(newcr);
+			}
+			break;
+		}
 		default:
 			*outlenp = 0;
 			return (EINVAL);
@@ -3346,32 +3544,27 @@
 		case IP_OPTIONS:
 		case T_IP_OPTIONS:
 			/* Save options for use by IP. */
-			if (inlen & 0x3) {
+			newlen = inlen + udp->udp_label_len;
+			if ((inlen & 0x3) || newlen > IP_MAX_OPT_LENGTH) {
 				*outlenp = 0;
 				return (EINVAL);
 			}
 			if (checkonly)
 				break;
 
-			if (udp->udp_ip_snd_options) {
-				mi_free((char *)udp->udp_ip_snd_options);
-				udp->udp_ip_snd_options_len = 0;
-				udp->udp_ip_snd_options = NULL;
+			if (!tsol_option_set(&udp->udp_ip_snd_options,
+			    &udp->udp_ip_snd_options_len,
+			    udp->udp_label_len, invalp, inlen)) {
+				*outlenp = 0;
+				return (ENOMEM);
 			}
-			if (inlen) {
-				udp->udp_ip_snd_options =
-					(uchar_t *)mi_alloc(inlen, BPRI_HI);
-				if (udp->udp_ip_snd_options) {
-					bcopy(invalp, udp->udp_ip_snd_options,
-					    inlen);
-					udp->udp_ip_snd_options_len = inlen;
-				}
-			}
+
 			udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH +
 			    UDPH_SIZE + udp->udp_ip_snd_options_len;
 			(void) mi_set_sth_wroff(RD(q), udp->udp_max_hdr_len +
 			    udp_wroff_extra);
 			break;
+
 		case IP_TTL:
 			if (!checkonly) {
 				udp->udp_ttl = (uchar_t)*i1;
@@ -3471,14 +3664,11 @@
 		/*
 		 * Deal with both sticky options and ancillary data
 		 */
-		if (thisdg_attrs == NULL) {
+		sticky = B_FALSE;
+		if (attrs == NULL || (ipp = attrs->udpattr_ipp) == NULL) {
 			/* sticky options, or none */
 			ipp = &udp->udp_sticky_ipp;
 			sticky = B_TRUE;
-		} else {
-			/* ancillary data */
-			ipp = (ip6_pkt_t *)thisdg_attrs;
-			sticky = B_FALSE;
 		}
 
 		switch (name) {
@@ -3739,22 +3929,16 @@
 			if (checkonly)
 				break;
 
-			if (inlen == 0) {
-				if (sticky &&
-				    (ipp->ipp_fields & IPPF_HOPOPTS) != 0) {
-					kmem_free(ipp->ipp_hopopts,
-					    ipp->ipp_hopoptslen);
-					ipp->ipp_hopopts = NULL;
-					ipp->ipp_hopoptslen = 0;
-				}
+			error = optcom_pkt_set(invalp, inlen, sticky,
+			    (uchar_t **)&ipp->ipp_hopopts,
+			    &ipp->ipp_hopoptslen,
+			    sticky ? udp->udp_label_len_v6 : 0);
+			if (error != 0)
+				return (error);
+			if (ipp->ipp_hopoptslen == 0) {
 				ipp->ipp_fields &= ~IPPF_HOPOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_HOPOPTS;
 			} else {
-				error = udp_pkt_set(invalp, inlen, sticky,
-				    (uchar_t **)&ipp->ipp_hopopts,
-				    &ipp->ipp_hopoptslen);
-				if (error != 0)
-					return (error);
 				ipp->ipp_fields |= IPPF_HOPOPTS;
 			}
 			if (sticky) {
@@ -3790,9 +3974,9 @@
 				ipp->ipp_fields &= ~IPPF_RTDSTOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_RTDSTOPTS;
 			} else {
-				error = udp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_rtdstopts,
-				    &ipp->ipp_rtdstoptslen);
+				    &ipp->ipp_rtdstoptslen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_RTDSTOPTS;
@@ -3829,9 +4013,9 @@
 				ipp->ipp_fields &= ~IPPF_DSTOPTS;
 				ipp->ipp_sticky_ignored |= IPPF_DSTOPTS;
 			} else {
-				error = udp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_dstopts,
-				    &ipp->ipp_dstoptslen);
+				    &ipp->ipp_dstoptslen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_DSTOPTS;
@@ -3868,9 +4052,9 @@
 				ipp->ipp_fields &= ~IPPF_RTHDR;
 				ipp->ipp_sticky_ignored |= IPPF_RTHDR;
 			} else {
-				error = udp_pkt_set(invalp, inlen, sticky,
+				error = optcom_pkt_set(invalp, inlen, sticky,
 				    (uchar_t **)&ipp->ipp_rthdr,
-				    &ipp->ipp_rthdrlen);
+				    &ipp->ipp_rthdrlen, 0);
 				if (error != 0)
 					return (error);
 				ipp->ipp_fields |= IPPF_RTHDR;
@@ -4018,46 +4202,6 @@
 }
 
 /*
- * Set optbuf and optlen for the option.
- * If sticky is set allocate memory (if not already present).
- * Otherwise just point optbuf and optlen at invalp and inlen.
- * Returns failure if memory can not be allocated.
- */
-static int
-udp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky,
-    uchar_t **optbufp, uint_t *optlenp)
-{
-	uchar_t *optbuf;
-
-	if (!sticky) {
-		*optbufp = invalp;
-		*optlenp = inlen;
-		return (0);
-	}
-	if (inlen == *optlenp) {
-		/* Unchanged length - no need to realocate */
-		bcopy(invalp, *optbufp, inlen);
-		return (0);
-	}
-	if (inlen != 0) {
-		/* Allocate new buffer before free */
-		optbuf = kmem_alloc(inlen, KM_NOSLEEP);
-		if (optbuf == NULL)
-			return (ENOMEM);
-	} else {
-		optbuf = NULL;
-	}
-	/* Free old buffer */
-	if (*optlenp != 0)
-		kmem_free(*optbufp, *optlenp);
-
-	bcopy(invalp, optbuf, inlen);
-	*optbufp = optbuf;
-	*optlenp = inlen;
-	return (0);
-}
-
-/*
  * This routine retrieves the value of an ND variable in a udpparam_t
  * structure.  It is called through nd_getset when a user reads the
  * variable.
@@ -4140,6 +4284,156 @@
 	return (0);
 }
 
+/*
+ * Copy hop-by-hop option from ipp->ipp_hopopts to the buffer provided (with
+ * T_opthdr) and return the number of bytes copied.  'dbuf' may be NULL to
+ * just count the length needed for allocation.  If 'dbuf' is non-NULL,
+ * then it's assumed to be allocated to be large enough.
+ *
+ * Returns zero if trimming of the security option causes all options to go
+ * away.
+ */
+static size_t
+copy_hop_opts(const ip6_pkt_t *ipp, uchar_t *dbuf)
+{
+	struct T_opthdr *toh;
+	size_t hol = ipp->ipp_hopoptslen;
+	ip6_hbh_t *dstopt = NULL;
+	const ip6_hbh_t *srcopt = ipp->ipp_hopopts;
+	size_t tlen, olen, plen;
+	boolean_t deleting;
+	const struct ip6_opt *sopt, *lastpad;
+	struct ip6_opt *dopt;
+
+	if ((toh = (struct T_opthdr *)dbuf) != NULL) {
+		toh->level = IPPROTO_IPV6;
+		toh->name = IPV6_HOPOPTS;
+		toh->status = 0;
+		dstopt = (ip6_hbh_t *)(toh + 1);
+	}
+
+	/*
+	 * If labeling is enabled, then skip the label option
+	 * but get other options if there are any.
+	 */
+	if (is_system_labeled()) {
+		dopt = NULL;
+		if (dstopt != NULL) {
+			/* will fill in ip6h_len later */
+			dstopt->ip6h_nxt = srcopt->ip6h_nxt;
+			dopt = (struct ip6_opt *)(dstopt + 1);
+		}
+		sopt = (const struct ip6_opt *)(srcopt + 1);
+		hol -= sizeof (*srcopt);
+		tlen = sizeof (*dstopt);
+		lastpad = NULL;
+		deleting = B_FALSE;
+		/*
+		 * This loop finds the first (lastpad pointer) of any number of
+		 * pads that preceeds the security option, then treats the
+		 * security option as though it were a pad, and then finds the
+		 * next non-pad option (or end of list).
+		 *
+		 * It then treats the entire block as one big pad.  To preserve
+		 * alignment of any options that follow, or just the end of the
+		 * list, it computes a minimal new padding size that keeps the
+		 * same alignment for the next option.
+		 *
+		 * If it encounters just a sequence of pads with no security
+		 * option, those are copied as-is rather than collapsed.
+		 *
+		 * Note that to handle the end of list case, the code makes one
+		 * loop with 'hol' set to zero.
+		 */
+		for (;;) {
+			if (hol > 0) {
+				if (sopt->ip6o_type == IP6OPT_PAD1) {
+					if (lastpad == NULL)
+						lastpad = sopt;
+					sopt = (const struct ip6_opt *)
+					    &sopt->ip6o_len;
+					hol--;
+					continue;
+				}
+				olen = sopt->ip6o_len + sizeof (*sopt);
+				if (olen > hol)
+					olen = hol;
+				if (sopt->ip6o_type == IP6OPT_PADN ||
+				    sopt->ip6o_type == ip6opt_ls) {
+					if (sopt->ip6o_type == ip6opt_ls)
+						deleting = B_TRUE;
+					if (lastpad == NULL)
+						lastpad = sopt;
+					sopt = (const struct ip6_opt *)
+					    ((const char *)sopt + olen);
+					hol -= olen;
+					continue;
+				}
+			} else {
+				/* if nothing was copied at all, then delete */
+				if (tlen == sizeof (*dstopt))
+					return (0);
+				/* last pass; pick up any trailing padding */
+				olen = 0;
+			}
+			if (deleting) {
+				/*
+				 * compute aligning effect of deleted material
+				 * to reproduce with pad.
+				 */
+				plen = ((const char *)sopt -
+				    (const char *)lastpad) & 7;
+				tlen += plen;
+				if (dopt != NULL) {
+					if (plen == 1) {
+						dopt->ip6o_type = IP6OPT_PAD1;
+					} else if (plen > 1) {
+						plen -= sizeof (*dopt);
+						dopt->ip6o_type = IP6OPT_PADN;
+						dopt->ip6o_len = plen;
+						if (plen > 0)
+							bzero(dopt + 1, plen);
+					}
+					dopt = (struct ip6_opt *)
+					    ((char *)dopt + plen);
+				}
+				deleting = B_FALSE;
+				lastpad = NULL;
+			}
+			/* if there's uncopied padding, then copy that now */
+			if (lastpad != NULL) {
+				olen += (const char *)sopt -
+				    (const char *)lastpad;
+				sopt = lastpad;
+				lastpad = NULL;
+			}
+			if (dopt != NULL && olen > 0) {
+				bcopy(sopt, dopt, olen);
+				dopt = (struct ip6_opt *)((char *)dopt + olen);
+			}
+			if (hol == 0)
+				break;
+			tlen += olen;
+			sopt = (const struct ip6_opt *)
+			    ((const char *)sopt + olen);
+			hol -= olen;
+		}
+		/* go back and patch up the length value, rounded upward */
+		if (dstopt != NULL)
+			dstopt->ip6h_len = (tlen - 1) >> 3;
+	} else {
+		tlen = hol;
+		if (dstopt != NULL)
+			bcopy(srcopt, dstopt, hol);
+	}
+
+	tlen += sizeof (*toh);
+	if (toh != NULL)
+		toh->len = tlen;
+
+	return (tlen);
+}
+
 static void
 udp_input(conn_t *connp, mblk_t *mp)
 {
@@ -4160,6 +4454,7 @@
 	cred_t			*cr = NULL;
 	queue_t			*q = connp->conn_rq;
 	pid_t			cpid;
+	cred_t			*rcr = connp->conn_cred;
 
 	TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_START,
 	    "udp_rput_start: q %p mp %p", q, mp);
@@ -4502,7 +4797,7 @@
 				toh->name = SCM_UCRED;
 				toh->len = sizeof (struct T_opthdr) + ucredsize;
 				toh->status = 0;
-				(void) cred2ucred(cr, cpid, &toh[1]);
+				(void) cred2ucred(cr, cpid, &toh[1], rcr);
 				dstopt += toh->len;
 				udi_size -= toh->len;
 			}
@@ -4563,9 +4858,13 @@
 		    IPPF_RTHDR|IPPF_IFINDEX)) {
 			if (udp->udp_ipv6_recvhopopts &&
 			    (ipp.ipp_fields & IPPF_HOPOPTS)) {
-				udi_size += sizeof (struct T_opthdr) +
-				    ipp.ipp_hopoptslen;
+				size_t hlen;
+
 				UDP_STAT(udp_in_recvhopopts);
+				hlen = copy_hop_opts(&ipp, NULL);
+				if (hlen == 0)
+					ipp.ipp_fields &= ~IPPF_HOPOPTS;
+				udi_size += hlen;
 			}
 			if ((udp->udp_ipv6_recvdstopts ||
 				udp->udp_old_ipv6_recvdstopts) &&
@@ -4731,19 +5030,11 @@
 			}
 			if (udp->udp_ipv6_recvhopopts &&
 			    (ipp.ipp_fields & IPPF_HOPOPTS)) {
-				struct T_opthdr *toh;
-
-				toh = (struct T_opthdr *)dstopt;
-				toh->level = IPPROTO_IPV6;
-				toh->name = IPV6_HOPOPTS;
-				toh->len = sizeof (struct T_opthdr) +
-				    ipp.ipp_hopoptslen;
-				toh->status = 0;
-				dstopt += sizeof (struct T_opthdr);
-				bcopy(ipp.ipp_hopopts, dstopt,
-				    ipp.ipp_hopoptslen);
-				dstopt += ipp.ipp_hopoptslen;
-				udi_size -= toh->len;
+				size_t hlen;
+
+				hlen = copy_hop_opts(&ipp, dstopt);
+				dstopt += hlen;
+				udi_size -= hlen;
 			}
 			if (udp->udp_ipv6_recvdstopts &&
 			    udp->udp_ipv6_recvrthdr &&
@@ -4803,7 +5094,7 @@
 				toh->name = SCM_UCRED;
 				toh->len = sizeof (struct T_opthdr) + ucredsize;
 				toh->status = 0;
-				(void) cred2ucred(cr, cpid, &toh[1]);
+				(void) cred2ucred(cr, cpid, &toh[1], rcr);
 				dstopt += toh->len;
 				udi_size -= toh->len;
 			}
@@ -4882,6 +5173,7 @@
 	cred_t			*cr = NULL;
 	udp_t			*udp = Q_TO_UDP(q);
 	pid_t			cpid;
+	cred_t			*rcr = udp->udp_connp->conn_cred;
 
 	TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_START,
 	    "udp_rput_other: q %p mp %p", q, mp);
@@ -5202,7 +5494,7 @@
 			toh->name = SCM_UCRED;
 			toh->len = sizeof (struct T_opthdr) + ucredsize;
 			toh->status = 0;
-			(void) cred2ucred(cr, cpid, &toh[1]);
+			(void) cred2ucred(cr, cpid, &toh[1], rcr);
 			dstopt += toh->len;
 			udi_size -= toh->len;
 		}
@@ -5376,32 +5668,40 @@
 {
 	mblk_t			*mpdata;
 	mblk_t			*mp_conn_ctl;
+	mblk_t			*mp_attr_ctl;
 	mblk_t			*mp6_conn_ctl;
-	mblk_t			*mp_conn_data;
-	mblk_t			*mp6_conn_data;
-	mblk_t			*mp_conn_tail = NULL;
-	mblk_t			*mp6_conn_tail = NULL;
+	mblk_t			*mp6_attr_ctl;
+	mblk_t			*mp_conn_tail;
+	mblk_t			*mp_attr_tail;
+	mblk_t			*mp6_conn_tail;
+	mblk_t			*mp6_attr_tail;
 	struct opthdr		*optp;
 	mib2_udpEntry_t		ude;
 	mib2_udp6Entry_t	ude6;
+	mib2_transportMLPEntry_t mlp;
 	int			state;
 	zoneid_t		zoneid;
 	int			i;
 	connf_t			*connfp;
 	conn_t			*connp = Q_TO_CONN(q);
 	udp_t			*udp = connp->conn_udp;
-
+	int			v4_conn_idx;
+	int			v6_conn_idx;
+	boolean_t		needattr;
+
+	mp_conn_ctl = mp_attr_ctl = mp6_conn_ctl = NULL;
 	if (mpctl == NULL ||
 	    (mpdata = mpctl->b_cont) == NULL ||
 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
-	    (mp6_conn_ctl = copymsg(mpctl)) == NULL) {
+	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_attr_ctl = copymsg(mpctl)) == NULL) {
 		freemsg(mp_conn_ctl);
+		freemsg(mp_attr_ctl);
+		freemsg(mp6_conn_ctl);
 		return (0);
 	}
 
-	mp_conn_data = mp_conn_ctl->b_cont;
-	mp6_conn_data = mp6_conn_ctl->b_cont;
-
 	zoneid = connp->conn_zoneid;
 
 	/* fixed length structure for IPv4 and IPv6 counters */
@@ -5414,6 +5714,9 @@
 	optp->len = msgdsize(mpdata);
 	qreply(q, mpctl);
 
+	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
+	v4_conn_idx = v6_conn_idx = 0;
+
 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
 		connfp = &ipcl_globalhash_fanout[i];
 		connp = NULL;
@@ -5438,6 +5741,18 @@
 			else
 				state = MIB2_UDP_unknown;
 
+			needattr = B_FALSE;
+			bzero(&mlp, sizeof (mlp));
+			if (connp->conn_mlp_type != mlptSingle) {
+				if (connp->conn_mlp_type == mlptShared ||
+				    connp->conn_mlp_type == mlptBoth)
+					mlp.tme_flags |= MIB2_TMEF_SHARED;
+				if (connp->conn_mlp_type == mlptPrivate ||
+				    connp->conn_mlp_type == mlptBoth)
+					mlp.tme_flags |= MIB2_TMEF_PRIVATE;
+				needattr = B_TRUE;
+			}
+
 			/*
 			 * Create an IPv4 table entry for IPv4 entries and also
 			 * any IPv6 entries which are bound to in6addr_any
@@ -5472,8 +5787,13 @@
 					ude.udpEntryInfo.ue_RemoteAddress = 0;
 					ude.udpEntryInfo.ue_RemotePort = 0;
 				}
-				(void) snmp_append_data2(mp_conn_data,
+				(void) snmp_append_data2(mp_conn_ctl->b_cont,
 				    &mp_conn_tail, (char *)&ude, sizeof (ude));
+				mlp.tme_connidx = v4_conn_idx++;
+				if (needattr)
+					(void) snmp_append_data2(
+					    mp_attr_ctl->b_cont, &mp_attr_tail,
+					    (char *)&mlp, sizeof (mlp));
 			}
 			if (udp->udp_ipversion == IPV6_VERSION) {
 				ude6.udp6EntryInfo.ue_state  = state;
@@ -5490,9 +5810,15 @@
 					    sin6_null.sin6_addr;
 					ude6.udp6EntryInfo.ue_RemotePort = 0;
 				}
-				(void) snmp_append_data2(mp6_conn_data,
+				(void) snmp_append_data2(mp6_conn_ctl->b_cont,
 				    &mp6_conn_tail, (char *)&ude6,
 				    sizeof (ude6));
+				mlp.tme_connidx = v6_conn_idx++;
+				if (needattr)
+					(void) snmp_append_data2(
+					    mp6_attr_ctl->b_cont,
+					    &mp6_attr_tail, (char *)&mlp,
+					    sizeof (mlp));
 			}
 		}
 	}
@@ -5502,17 +5828,39 @@
 	    sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_UDP;
 	optp->name = MIB2_UDP_ENTRY;
-	optp->len = msgdsize(mp_conn_data);
+	optp->len = msgdsize(mp_conn_ctl->b_cont);
 	qreply(q, mp_conn_ctl);
 
+	/* table of MLP attributes... */
+	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_UDP;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp_attr_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp_attr_ctl);
+	else
+		qreply(q, mp_attr_ctl);
+
 	/* IPv6 UDP endpoints */
 	optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
 	    sizeof (struct T_optmgmt_ack)];
 	optp->level = MIB2_UDP6;
 	optp->name = MIB2_UDP6_ENTRY;
-	optp->len = msgdsize(mp6_conn_data);
+	optp->len = msgdsize(mp6_conn_ctl->b_cont);
 	qreply(q, mp6_conn_ctl);
 
+	/* table of MLP attributes... */
+	optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_UDP6;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp6_attr_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp6_attr_ctl);
+	else
+		qreply(q, mp6_attr_ctl);
+
 	return (1);
 }
 
@@ -5733,15 +6081,17 @@
 
 /*
  * Don't let port fall into the privileged range.
- * Since the extra priviledged ports can be arbitrary we also
+ * Since the extra privileged ports can be arbitrary we also
  * ensure that we exclude those from consideration.
  * udp_g_epriv_ports is not sorted thus we loop over it until
  * there are no changes.
  */
 static in_port_t
-udp_update_next_port(in_port_t port, boolean_t random)
+udp_update_next_port(udp_t *udp, in_port_t port, boolean_t random)
 {
 	int i;
+	in_port_t nextport;
+	boolean_t restart = B_FALSE;
 
 	if (random && udp_random_anon_port != 0) {
 		(void) random_get_pseudo_bytes((uint8_t *)&port,
@@ -5763,8 +6113,15 @@
 	}
 
 retry:
-	if (port < udp_smallest_anon_port || port > udp_largest_anon_port)
+	if (port < udp_smallest_anon_port)
+		port = udp_smallest_anon_port;
+
+	if (port > udp_largest_anon_port) {
 		port = udp_smallest_anon_port;
+		if (restart)
+			return (0);
+		restart = B_TRUE;
+	}
 
 	if (port < udp_smallest_nonpriv_port)
 		port = udp_smallest_nonpriv_port;
@@ -5779,27 +6136,103 @@
 			goto retry;
 		}
 	}
+
+	if (is_system_labeled() &&
+	    (nextport = tsol_next_port(crgetzone(udp->udp_connp->conn_cred),
+	    port, IPPROTO_UDP, B_TRUE)) != 0) {
+		port = nextport;
+		goto retry;
+	}
+
 	return (port);
 }
 
+static int
+udp_update_label(queue_t *wq, mblk_t *mp, ipaddr_t dst)
+{
+	int err;
+	uchar_t opt_storage[IP_MAX_OPT_LENGTH];
+	udp_t *udp = Q_TO_UDP(wq);
+
+	err = tsol_compute_label(DB_CREDDEF(mp, udp->udp_connp->conn_cred), dst,
+	    opt_storage, udp->udp_mac_exempt);
+	if (err == 0) {
+		err = tsol_update_options(&udp->udp_ip_snd_options,
+		    &udp->udp_ip_snd_options_len, &udp->udp_label_len,
+		    opt_storage);
+	}
+	if (err != 0) {
+		DTRACE_PROBE4(
+		    tx__ip__log__info__updatelabel__udp,
+		    char *, "queue(1) failed to update options(2) on mp(3)",
+		    queue_t *, wq, char *, opt_storage, mblk_t *, mp);
+	} else {
+		IN6_IPADDR_TO_V4MAPPED(dst, &udp->udp_v6lastdst);
+	}
+	return (err);
+}
+
 static mblk_t *
 udp_output_v4(conn_t *connp, mblk_t *mp, ipaddr_t v4dst, uint16_t port,
     uint_t srcid, int *error)
 {
 	udp_t	*udp = connp->conn_udp;
 	queue_t	*q = connp->conn_wq;
-	mblk_t	*mp1 = (DB_TYPE(mp) == M_DATA ? mp : mp->b_cont);
+	mblk_t	*mp1 = mp;
 	mblk_t	*mp2;
 	ipha_t	*ipha;
 	int	ip_hdr_length;
 	uint32_t ip_len;
 	udpha_t	*udpha;
+	udpattrs_t	attrs;
 
 	*error = 0;
 
+	if (v4dst == INADDR_ANY)
+		v4dst = htonl(INADDR_LOOPBACK);
+
+	/*
+	 * If options passed in, feed it for verification and handling
+	 */
+	attrs.udpattr_credset = B_FALSE;
+	if (DB_TYPE(mp) != M_DATA) {
+		mp1 = mp->b_cont;
+		if (((struct T_unitdata_req *)mp->b_rptr)->OPT_length != 0) {
+			attrs.udpattr_ipp = NULL;
+			attrs.udpattr_mb = mp;
+			if (udp_unitdata_opt_process(q, mp, error, &attrs) < 0)
+				goto done;
+			/*
+			 * Note: success in processing options.
+			 * mp option buffer represented by
+			 * OPT_length/offset now potentially modified
+			 * and contain option setting results
+			 */
+			ASSERT(*error == 0);
+		}
+	}
+
 	/* mp1 points to the M_DATA mblk carrying the packet */
 	ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA);
 
+	/* Check if our saved options are valid; update if not */
+	if (is_system_labeled()) {
+		/* Using UDP MLP requires SCM_UCRED from user */
+		if (connp->conn_mlp_type != mlptSingle &&
+		    !attrs.udpattr_credset) {
+			DTRACE_PROBE4(
+			    tx__ip__log__info__output__udp,
+			    char *, "MLP mp(1) lacks SCM_UCRED attr(2) on q(3)",
+			    mblk_t *, mp1, udpattrs_t *, &attrs, queue_t *, q);
+			*error = ECONNREFUSED;
+			goto done;
+		}
+		if ((!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6lastdst) ||
+		    V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst) &&
+		    (*error = udp_update_label(q, mp, v4dst)) != 0)
+			goto done;
+	}
+
 	/* Add an IP header */
 	ip_hdr_length = IP_SIMPLE_HDR_LENGTH + UDPH_SIZE +
 	    udp->udp_ip_snd_options_len;
@@ -5887,10 +6320,7 @@
 	/*
 	 * Copy in the destination address
 	 */
-	if (v4dst == INADDR_ANY)
-		ipha->ipha_dst = htonl(INADDR_LOOPBACK);
-	else
-		ipha->ipha_dst = v4dst;
+	ipha->ipha_dst = v4dst;
 
 	/*
 	 * Set ttl based on IP_MULTICAST_TTL to match IPv6 logic.
@@ -5951,6 +6381,8 @@
 	}
 	/* Set UDP length and checksum */
 	*((uint32_t *)&udpha->uha_length) = ip_len;
+	if (DB_CRED(mp) != NULL)
+		mblk_setcred(mp1, DB_CRED(mp));
 
 	if (DB_TYPE(mp) != M_DATA) {
 		ASSERT(mp != mp1);
@@ -6059,10 +6491,12 @@
 		if (CLASSD(dst)) {
 			ASSERT(ipif != NULL);
 			ire = ire_ctable_lookup(dst, 0, 0, ipif,
-			    connp->conn_zoneid, MATCH_IRE_ILL_GROUP);
+			    connp->conn_zoneid, MBLK_GETLABEL(mp),
+			    MATCH_IRE_ILL_GROUP);
 		} else {
 			ASSERT(ipif == NULL);
-			ire = ire_cache_lookup(dst, connp->conn_zoneid);
+			ire = ire_cache_lookup(dst, connp->conn_zoneid,
+			    MBLK_GETLABEL(mp));
 		}
 
 		if (ire == NULL) {
@@ -6226,6 +6660,30 @@
 	IRE_REFRELE(ire);
 }
 
+static boolean_t
+udp_update_label_v6(queue_t *wq, mblk_t *mp, in6_addr_t *dst)
+{
+	udp_t *udp = Q_TO_UDP(wq);
+	int err;
+	uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
+
+	err = tsol_compute_label_v6(DB_CREDDEF(mp, udp->udp_connp->conn_cred),
+	    dst, opt_storage, udp->udp_mac_exempt);
+	if (err == 0) {
+		err = tsol_update_sticky(&udp->udp_sticky_ipp,
+		    &udp->udp_label_len_v6, opt_storage);
+	}
+	if (err != 0) {
+		DTRACE_PROBE4(
+		    tx__ip__log__drop__updatelabel__udp6,
+		    char *, "queue(1) failed to update options(2) on mp(3)",
+		    queue_t *, wq, char *, opt_storage, mblk_t *, mp);
+	} else {
+		udp->udp_v6lastdst = *dst;
+	}
+	return (err);
+}
+
 /*
  * This routine handles all messages passed downstream.  It either
  * consumes the message or passes it downstream; it never queues a
@@ -6241,7 +6699,6 @@
 	uint_t		srcid;
 	queue_t		*q = connp->conn_wq;
 	udp_t		*udp = connp->conn_udp;
-	t_scalar_t	optlen;
 	int		error = 0;
 	struct sockaddr_storage ss;
 
@@ -6271,7 +6728,6 @@
 			ASSERT(udp->udp_issocket);
 			UDP_DBGSTAT(udp_data_notconn);
 			/* Not connected; do some more checks below */
-			optlen = 0;
 			break;
 		}
 		/* M_DATA for connected socket */
@@ -6310,7 +6766,7 @@
 			mp = udp_output_v4(connp, mp, v4dst,
 			    udp->udp_dstport, 0, &error);
 		} else {
-			mp = udp_output_v6(connp, mp, sin6, 0, &error);
+			mp = udp_output_v6(connp, mp, sin6, &error);
 		}
 		if (error != 0) {
 			ASSERT(addr != NULL && addrlen != 0);
@@ -6356,8 +6812,7 @@
 			addr = (struct sockaddr *)
 			    &mp->b_rptr[tudr->DEST_offset];
 			addrlen = tudr->DEST_length;
-			optlen = tudr->OPT_length;
-			if (optlen != 0)
+			if (tudr->OPT_length != 0)
 				UDP_STAT(udp_out_opt);
 			break;
 		}
@@ -6386,7 +6841,7 @@
 			 * Destination is a non-IPv4-compatible IPv6 address.
 			 * Send out an IPv6 format packet.
 			 */
-			mp = udp_output_v6(connp, mp, sin6, optlen, &error);
+			mp = udp_output_v6(connp, mp, sin6, &error);
 			if (error != 0)
 				goto ud_error;
 
@@ -6430,26 +6885,6 @@
 		break;
 	}
 
-	/*
-	 * If options passed in, feed it for verification and handling
-	 */
-	if (optlen != 0) {
-		ASSERT(DB_TYPE(mp) != M_DATA);
-		if (udp_unitdata_opt_process(q, mp, &error, NULL) < 0) {
-			/* failure */
-			TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END,
-			    "udp_wput_end: q %p (%S)", q,
-			    "udp_unitdata_opt_process");
-			goto ud_error;
-		}
-		/*
-		 * Note: success in processing options.
-		 * mp option buffer represented by
-		 * OPT_length/offset now potentially modified
-		 * and contain option setting results
-		 */
-	}
-	ASSERT(error == 0);
 	mp = udp_output_v4(connp, mp, v4dst, port, srcid, &error);
 	if (error != 0) {
 ud_error:
@@ -6566,12 +7001,11 @@
  * address.
  */
 static mblk_t *
-udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen,
-    int *error)
+udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, int *error)
 {
 	ip6_t		*ip6h;
 	ip6i_t		*ip6i;	/* mp1->b_rptr even if no ip6i_t */
-	mblk_t		*mp1 = (DB_TYPE(mp) == M_DATA ? mp : mp->b_cont);
+	mblk_t		*mp1 = mp;
 	mblk_t		*mp2;
 	int		udp_ip_hdr_len = IPV6_HDR_LEN + UDPH_SIZE;
 	size_t		ip_len;
@@ -6586,13 +7020,12 @@
 	uint_t		option_exists = 0, is_sticky = 0;
 	uint8_t		*cp;
 	uint8_t		*nxthdr_ptr;
+	in6_addr_t	ip6_dst;
+	udpattrs_t	attrs;
+	boolean_t	opt_present;
 
 	*error = 0;
 
-	/* mp1 points to the M_DATA mblk carrying the packet */
-	ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA);
-	ASSERT(tudr_optlen == 0 || DB_TYPE(mp) != M_DATA);
-
 	/*
 	 * If the local address is a mapped address return
 	 * an error.
@@ -6611,14 +7044,23 @@
 	/*
 	 * If TPI options passed in, feed it for verification and handling
 	 */
-	if (tudr_optlen != 0) {
-		if (udp_unitdata_opt_process(q, mp, error, (void *)ipp) < 0) {
-			/* failure */
-			goto done;
-		}
-		ignore = ipp->ipp_sticky_ignored;
-		ASSERT(*error == 0);
-	}
+	attrs.udpattr_credset = B_FALSE;
+	opt_present = B_FALSE;
+	if (DB_TYPE(mp) != M_DATA) {
+		mp1 = mp->b_cont;
+		if (((struct T_unitdata_req *)mp->b_rptr)->OPT_length != 0) {
+			attrs.udpattr_ipp = ipp;
+			attrs.udpattr_mb = mp;
+			if (udp_unitdata_opt_process(q, mp, error, &attrs) < 0)
+				goto done;
+			ASSERT(*error == 0);
+			opt_present = B_TRUE;
+		}
+	}
+	ignore = ipp->ipp_sticky_ignored;
+
+	/* mp1 points to the M_DATA mblk carrying the packet */
+	ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA);
 
 	if (sin6->sin6_scope_id != 0 &&
 	    IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
@@ -6630,6 +7072,45 @@
 		option_exists |= IPPF_SCOPE_ID;
 	}
 
+	/*
+	 * Compute the destination address
+	 */
+	ip6_dst = sin6->sin6_addr;
+	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+		ip6_dst = ipv6_loopback;
+
+	/*
+	 * If we're not going to the same destination as last time, then
+	 * recompute the label required.  This is done in a separate routine to
+	 * avoid blowing up our stack here.
+	 */
+	if (is_system_labeled()) {
+		/* Using UDP MLP requires SCM_UCRED from user */
+		if (connp->conn_mlp_type != mlptSingle &&
+		    !attrs.udpattr_credset) {
+			DTRACE_PROBE4(
+			    tx__ip__log__info__output__udp6,
+			    char *, "MLP mp(1) lacks SCM_UCRED attr(2) on q(3)",
+			    mblk_t *, mp1, udpattrs_t *, &attrs, queue_t *, q);
+			*error = ECONNREFUSED;
+			goto done;
+		}
+		if ((opt_present ||
+		    !IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst)) &&
+		    (*error = udp_update_label_v6(q, mp, &ip6_dst)) != 0)
+			goto done;
+	}
+
+	/*
+	 * If there's a security label here, then we ignore any options the
+	 * user may try to set.  We keep the peer's label as a hidden sticky
+	 * option.
+	 */
+	if (udp->udp_label_len_v6 > 0) {
+		ignore &= ~IPPF_HOPOPTS;
+		ipp->ipp_fields &= ~IPPF_HOPOPTS;
+	}
+
 	if ((udp->udp_sticky_ipp.ipp_fields == 0) && (ipp->ipp_fields == 0)) {
 		/* No sticky options nor ancillary data. */
 		goto no_options;
@@ -6944,10 +7425,7 @@
 	/*
 	 * Copy in the destination address
 	 */
-	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
-		ip6h->ip6_dst = ipv6_loopback;
-	else
-		ip6h->ip6_dst = sin6->sin6_addr;
+	ip6h->ip6_dst = ip6_dst;
 
 	ip6h->ip6_vcf =
 	    (IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) |
@@ -7045,6 +7523,8 @@
 	ip_len = htons(ip_len);
 #endif
 	ip6h->ip6_plen = ip_len;
+	if (DB_CRED(mp) != NULL)
+		mblk_setcred(mp1, DB_CRED(mp));
 
 	if (DB_TYPE(mp) != M_DATA) {
 		ASSERT(mp != mp1);
@@ -7459,7 +7939,7 @@
 
 static int
 udp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp,
-    void *thisdg_attrs)
+    udpattrs_t *udpattrs)
 {
 	struct T_unitdata_req *udreqp;
 	int is_absreq_failure;
@@ -7471,7 +7951,6 @@
 	cr = DB_CREDDEF(mp, connp->conn_cred);
 
 	udreqp = (struct T_unitdata_req *)mp->b_rptr;
-	*errorp = 0;
 
 	/*
 	 * Use upper queue for option processing since the callback
@@ -7479,7 +7958,7 @@
 	 */
 	*errorp = tpi_optcom_buf(_WR(UDP_RD(q)), mp, &udreqp->OPT_length,
 	    udreqp->OPT_offset, cr, &udp_opt_obj,
-	    thisdg_attrs, &is_absreq_failure);
+	    udpattrs, &is_absreq_failure);
 
 	if (*errorp != 0) {
 		/*
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c	Fri Mar 24 12:29:20 2006 -0800
@@ -36,6 +36,7 @@
 #include <inet/common.h>
 #include <netinet/ip6.h>
 #include <inet/ip.h>
+#include <inet/udp_impl.h>
 /*
  * MK_XXX Following 2 includes temporary to import ip6_rthdr_t
  *        definition. May not be needed if we fix ip6_dg_snd_attrs_t
@@ -45,19 +46,9 @@
 #include <inet/ip6.h>
 
 #include <netinet/in.h>
-#include <netinet/tcp.h>
 #include <netinet/udp.h>
-#include <netinet/ip_mroute.h>
 #include <inet/optcom.h>
 
-extern int	udp_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name,
-    uchar_t *ptr);
-extern int	udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name,
-    uchar_t *ptr);
-extern int	udp_opt_set(queue_t *q, uint_t optset_context,
-    int level, int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
-    uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk);
-
 /*
  * Table of all known options handled on a UDP protocol stack.
  *
@@ -82,6 +73,12 @@
 	},
 { SO_TIMESTAMP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0
 	},
+{ SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
+{ SCM_UCRED, SOL_SOCKET, OA_W, OA_W, OP_NP, OP_VARLEN|OP_NODEFAULT, 512, 0 },
+
 { IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
 	(OP_PASSNEXT|OP_VARLEN|OP_NODEFAULT), 40, -1 /* not initialized */ },
 { T_IP_OPTIONS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP,
--- a/usr/src/uts/common/inet/udp_impl.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/inet/udp_impl.h	Fri Mar 24 12:29:20 2006 -0800
@@ -48,6 +48,7 @@
 
 #include <inet/common.h>
 #include <inet/ip.h>
+#include <inet/optcom.h>
 
 #define	UDP_MOD_ID		5607
 
@@ -122,7 +123,9 @@
 		udp_direct_sockfs : 1,	/* direct calls to/from sockfs */
 
 		udp_timestamp : 1,	/* SO_TIMESTAMP "socket" option */
-		udp_pad_to_bit_31 : 3;
+		udp_anon_mlp : 1,		/* SO_ANON_MLP */
+		udp_mac_exempt : 1,		/* SO_MAC_EXEMPT */
+		udp_pad_to_bit_31 : 1;
 
 	uint8_t		udp_type_of_service;	/* IP_TOS option */
 	uint8_t		udp_ttl;		/* TTL or hoplimit */
@@ -146,6 +149,9 @@
 	uint_t		udp_rcv_cnt;		/* total data in rcv_list */
 	uint_t		udp_rcv_msgcnt;		/* total messages in rcv_list */
 	size_t		udp_rcv_hiwat;		/* receive high watermark */
+	uint_t		udp_label_len;		/* length of security label */
+	uint_t		udp_label_len_v6;	/* len of v6 security label */
+	in6_addr_t 	udp_v6lastdst;		/* most recent destination */
 } udp_t;
 
 /* UDP Protocol header */
@@ -156,7 +162,6 @@
 	uint16_t	uha_length;		/* UDP length */
 	uint16_t	uha_checksum;		/* UDP checksum */
 } udpha_t;
-#define	UDPH_SIZE	8
 
 /* Named Dispatch Parameter Management Structure */
 typedef struct udpparam_s {
@@ -245,6 +250,22 @@
 extern void	udp_wput_data(queue_t *, mblk_t *, struct sockaddr *,
 		    socklen_t);
 
+extern int	udp_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name,
+    uchar_t *ptr);
+extern int	udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name,
+    uchar_t *ptr);
+extern int	udp_opt_set(queue_t *q, uint_t optset_context,
+    int level, int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
+    uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk);
+
+/*
+ * Object to represent database of options to search passed to
+ * {sock,tpi}optcom_req() interface routine to take care of option
+ * management and associated methods.
+ */
+extern optdb_obj_t	udp_opt_obj;
+extern uint_t		udp_max_optsize;
+
 #endif	/*  _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/io/tl.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/io/tl.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -863,7 +862,7 @@
 static void tl_icon_sendmsgs(tl_endpt_t *, mblk_t **);
 static void tl_icon_freemsgs(mblk_t **);
 static void tl_merror(queue_t *, mblk_t *, int);
-static void tl_fill_option(uchar_t *, cred_t *, pid_t, int);
+static void tl_fill_option(uchar_t *, cred_t *, pid_t, int, cred_t *);
 static int tl_default_opt(queue_t *, int, int, uchar_t *);
 static int tl_get_opt(queue_t *, int, int, uchar_t *);
 static int tl_set_opt(queue_t *, uint_t, int, int, uint_t, uchar_t *, uint_t *,
@@ -3242,7 +3241,7 @@
 		tl_fill_option(cimp->b_rptr + ci->OPT_offset,
 			DB_CREDDEF(cimp, tep->te_credp),
 			TLPID(cimp, tep),
-			peer_tep->te_flag);
+			peer_tep->te_flag, peer_tep->te_credp);
 	} else if (ooff != 0) {
 		/* Copy option from T_CONN_REQ */
 		ci->OPT_offset = (t_scalar_t)T_ALIGN(ci->SRC_offset +
@@ -3723,7 +3722,8 @@
 			    cc->RES_length);
 			cc->OPT_length = olen;
 			tl_fill_option(ccmp->b_rptr + cc->OPT_offset,
-			    acc_ep->te_credp, acc_ep->te_cpid, cl_ep->te_flag);
+			    acc_ep->te_credp, acc_ep->te_cpid, cl_ep->te_flag,
+			    cl_ep->te_credp);
 		} else {
 			cc->OPT_offset = 0;
 			cc->OPT_length = 0;
@@ -5212,7 +5212,7 @@
 			tl_fill_option(ui_mp->b_rptr + udind->OPT_offset +
 			    oldolen,
 			    DB_CREDDEF(mp, tep->te_credp), TLPID(mp, tep),
-			    peer_tep->te_flag);
+			    peer_tep->te_flag, peer_tep->te_credp);
 		} else {
 			bcopy((void *)((uintptr_t)udreq + ooff),
 				(void *)((uintptr_t)udind + udind->OPT_offset),
@@ -5928,7 +5928,7 @@
 }
 
 static void
-tl_fill_option(uchar_t *buf, cred_t *cr, pid_t cpid, int flag)
+tl_fill_option(uchar_t *buf, cred_t *cr, pid_t cpid, int flag, cred_t *pcr)
 {
 	if (flag & TL_SETCRED) {
 		struct opthdr *opt = (struct opthdr *)buf;
@@ -5953,7 +5953,7 @@
 		opt->name = TL_OPT_PEER_UCRED;
 		opt->len = (t_uscalar_t)OPTLEN(ucredsize);
 
-		(void) cred2ucred(cr, cpid, (void *)(opt + 1));
+		(void) cred2ucred(cr, cpid, (void *)(opt + 1), pcr);
 	} else {
 		struct T_opthdr *topt = (struct T_opthdr *)buf;
 		ASSERT(flag & TL_SOCKUCRED);
@@ -5962,7 +5962,7 @@
 		topt->name = SCM_UCRED;
 		topt->len = ucredsize + sizeof (*topt);
 		topt->status = 0;
-		(void) cred2ucred(cr, cpid, (void *)(topt + 1));
+		(void) cred2ucred(cr, cpid, (void *)(topt + 1), pcr);
 	}
 }
 
--- a/usr/src/uts/common/net/route.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/net/route.h	Fri Mar 24 12:29:20 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 1992-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -48,6 +48,9 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 /* from UCB 8.5 (Berkeley) 2/8/95 */
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -219,6 +222,38 @@
 #define	RTAX_SRCIFP	9
 #define	RTAX_MAX	RTA_NUMBITS	/* size of array to allocate */
 
+/*
+ * Routing socket message extension after sockaddrs.
+ */
+typedef struct rtm_ext_s {
+	uint32_t	rtmex_type;	/* identifier for type of extension */
+	uint32_t	rtmex_len;	/* length of this extension */
+} rtm_ext_t;
+
+#define	RTMEX_GATEWAY_SECATTR	1	/* extension is tsol_rtsecattr */
+#define	RTMEX_MAX	RTMEX_GATEWAY_SECATTR
+
+/*
+ * Trusted Solaris route security attributes extension.
+ */
+typedef struct tsol_rtsecattr_s {
+	uint32_t	rtsa_cnt;	/* number of attributes */
+	struct rtsa_s {
+		uint32_t rtsa_mask;	/* see RTSA_* below */
+		uint32_t rtsa_doi;	/* domain of interpretation */
+		brange_t rtsa_slrange;	/* sensitivity label range */
+	} rtsa_attr[1];
+} tsol_rtsecattr_t;
+
+#define	TSOL_RTSECATTR_SIZE(n) \
+	(sizeof (tsol_rtsecattr_t) + (((n) - 1) * sizeof (struct rtsa_s)))
+
+#define	RTSA_MINSL	0x1	/* minimum sensitivity label is valid */
+#define	RTSA_MAXSL	0x2	/* maximum sensitivity label is valid */
+#define	RTSA_DOI	0x4	/* domain of interpretation is valid */
+#define	RTSA_CIPSO	0x100	/* CIPSO protocol */
+#define	RTSA_SLRANGE (RTSA_MINSL|RTSA_MAXSL)
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/netinet/ip6.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/netinet/ip6.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -155,6 +153,10 @@
 #define	IP6OPT_HOME_ADDRESS		0xc9	/* 11 0 01001 */
 #define	IP6OPT_EID			0x8a	/* 10 0 01010 */
 
+#define	IP6OPT_LS			0x0a	/* 00 0 01010 */
+
+#define	IP6_MAX_OPT_LENGTH	255
+
 /* Jumbo Payload Option */
 struct	ip6_opt_jumbo {
 	uint8_t	ip6oj_type;
@@ -242,6 +244,23 @@
 	/* Followed by sub-options */
 };
 
+/* Labeled Security Option */
+struct	ip6_opt_labeled_security {
+	uint8_t ip6ol_type;
+	uint8_t ip6ol_len;	/* always even for defined values */
+	uint8_t ip6ol_doi[4];
+	/* Followed by sub-options */
+};
+
+#define	IP6LS_DOI_V4	0	/* IPv4 transition */
+
+#define	IP6LS_TT_LEVEL	1	/* level or classification; 2-octet value */
+#define	IP6LS_TT_VECTOR	2	/* compartments; bit vector (even # octets) */
+#define	IP6LS_TT_ENUM	3	/* set membership; list of 2-octet values */
+#define	IP6LS_TT_RANGES	4	/* set membership; pairs of 2-octet values */
+#define	IP6LS_TT_V4	5	/* IPv4 compatible option */
+#define	IP6LS_TT_DEST	6	/* destination-only data; per DOI */
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/nfs/nfs.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/nfs/nfs.h	Fri Mar 24 12:29:20 2006 -0800
@@ -38,10 +38,12 @@
 #include <rpc/types.h>
 #include <sys/types32.h>
 #ifdef _KERNEL
-#include <rpc/xdr.h>
+#include <rpc/rpc.h>
 #include <sys/fcntl.h>
 #include <sys/kstat.h>
 #include <sys/dirent.h>
+#include <sys/zone.h>
+#include <sys/tsol/label.h>
 #include <nfs/mount.h>
 #endif
 #include <vm/page.h>
@@ -926,6 +928,8 @@
 extern void	nfsauth_init();
 extern void	nfsauth_fini();
 extern int	nfs_setopts(vnode_t *vp, model_t model, struct nfs_args *args);
+extern int	nfs_mount_label_policy(vfs_t *vfsp, struct netbuf *addr,
+		    struct knetconfig *knconf, cred_t *cr);
 extern void	nfs_srv_stop_all(void);
 extern void	nfs_srv_quiesce_all(void);
 extern void	(*nfs_srv_quiesce_func)(void);
--- a/usr/src/uts/common/os/cred.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/cred.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,9 +49,7 @@
 #include <sys/kmem.h>
 #include <sys/user.h>
 #include <sys/proc.h>
-#include <sys/acct.h>
 #include <sys/syscall.h>
-#include <sys/cmn_err.h>
 #include <sys/debug.h>
 #include <sys/atomic.h>
 #include <sys/ucred.h>
@@ -60,12 +57,14 @@
 #include <sys/modctl.h>
 #include <c2/audit.h>
 #include <sys/zone.h>
+#include <sys/tsol/label.h>
 
 static struct kmem_cache *cred_cache;
 static size_t crsize = 0;
 static int audoff = 0;
 uint32_t ucredsize;
 cred_t *kcred;
+static cred_t *dummycr;
 
 int rstlink;		/* link(2) restricted to files owned by user? */
 
@@ -74,6 +73,7 @@
 #define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
 			    ((char *)(c)) + audoff)
 
+#define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
 
 /*
  * Initialize credentials data structures.
@@ -106,6 +106,19 @@
 		NULL, NULL, NULL, NULL, NULL, 0);
 
 	/*
+	 * dummycr is used to copy initial state for creds.
+	 */
+	dummycr = cralloc();
+	bzero(dummycr, crsize);
+	dummycr->cr_ref = 1;
+	dummycr->cr_uid = -1;
+	dummycr->cr_gid = -1;
+	dummycr->cr_ruid = -1;
+	dummycr->cr_rgid = -1;
+	dummycr->cr_suid = -1;
+	dummycr->cr_sgid = -1;
+
+	/*
 	 * kcred is used by anything that needs all privileges; it's
 	 * also the template used for crget as it has all the compatible
 	 * sets filled in.
@@ -130,7 +143,8 @@
 		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
 
 	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
-	/* CR_FLAGS(kcred) == 0, courtesy of bzero() */
+
+	CR_FLAGS(kcred) = NET_MAC_AWARE;
 
 	/*
 	 * Set up credentials of p0.
@@ -150,6 +164,7 @@
 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
 	cr->cr_ref = 1;		/* So we can crfree() */
 	cr->cr_zone = NULL;
+	cr->cr_label = NULL;
 	return (cr);
 }
 
@@ -165,6 +180,8 @@
 	bcopy(kcred, cr, crsize);
 	cr->cr_ref = 1;
 	zone_cred_hold(cr->cr_zone);
+	if (cr->cr_label)
+		label_hold(cr->cr_label);
 	return (cr);
 }
 
@@ -220,12 +237,15 @@
 
 /*
  * 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_zone)
 			zone_cred_rele(cr->cr_zone);
 		kmem_cache_free(cred_cache, cr);
@@ -246,6 +266,8 @@
 	bcopy(cr, newcr, crsize);
 	if (newcr->cr_zone)
 		zone_cred_hold(newcr->cr_zone);
+	if (newcr->cr_label)
+		label_hold(cr->cr_label);
 	crfree(cr);
 	newcr->cr_ref = 2;		/* caller gets two references */
 	return (newcr);
@@ -264,6 +286,8 @@
 	bcopy(oldcr, newcr, crsize);
 	if (newcr->cr_zone)
 		zone_cred_hold(newcr->cr_zone);
+	if (newcr->cr_label)
+		label_hold(newcr->cr_label);
 	crfree(oldcr);
 	newcr->cr_ref = 2;		/* caller gets two references */
 }
@@ -281,6 +305,8 @@
 	bcopy(cr, newcr, crsize);
 	if (newcr->cr_zone)
 		zone_cred_hold(newcr->cr_zone);
+	if (newcr->cr_label)
+		label_hold(newcr->cr_label);
 	newcr->cr_ref = 1;
 	return (newcr);
 }
@@ -297,6 +323,8 @@
 	bcopy(oldcr, newcr, crsize);
 	if (newcr->cr_zone)
 		zone_cred_hold(newcr->cr_zone);
+	if (newcr->cr_label)
+		label_hold(newcr->cr_label);
 	newcr->cr_ref = 1;
 }
 
@@ -304,7 +332,7 @@
  * Return the (held) credentials for the current running process.
  */
 cred_t *
-crgetcred()
+crgetcred(void)
 {
 	cred_t *cr;
 	proc_t *p;
@@ -500,7 +528,9 @@
 zoneid_t
 crgetzoneid(const cred_t *cr)
 {
-	return (cr->cr_zone->zone_id);
+	return (cr->cr_zone == NULL ?
+	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
+	    cr->cr_zone->zone_id);
 }
 
 projid_t
@@ -509,6 +539,26 @@
 	return (cr->cr_projid);
 }
 
+zone_t *
+crgetzone(const cred_t *cr)
+{
+	return (cr->cr_zone);
+}
+
+struct ts_label_s *
+crgetlabel(const cred_t *cr)
+{
+	return (cr->cr_label ?
+	    cr->cr_label :
+	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
+}
+
+boolean_t
+crisremote(const cred_t *cr)
+{
+	return (REMOTE_PEER_CRED(cr));
+}
+
 #define	BADID(x)	((x) != -1 && (unsigned int)(x) > MAXUID)
 
 int
@@ -618,12 +668,12 @@
 }
 
 static int
-cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo)
+cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
 {
 	auditinfo_addr_t	*ai;
 	au_tid_addr_t	tid;
 
-	if (secpolicy_audit_getattr(CRED()) != 0)
+	if (secpolicy_audit_getattr(rcr) != 0)
 		return (-1);
 
 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
@@ -642,13 +692,26 @@
 	return (0);
 }
 
+void
+cred2uclabel(const cred_t *cr, bslabel_t *labelp)
+{
+	ts_label_t	*tslp;
+
+	if ((tslp = crgetlabel(cr)) != NULL)
+		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
+}
+
 /*
  * Convert a credential into a "ucred".  Allow the caller to specify
  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
  * memory and copy it twice.
+ *
+ * This function may call cred2ucaud(), which calls CRED(). Since this
+ * can be called from an interrupt thread, receiver's cred (rcr) is needed
+ * to determine whether audit info should be included.
  */
 struct ucred_s *
-cred2ucred(const cred_t *cr, pid_t pid, void *buf)
+cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
 {
 	struct ucred_s *uc;
 
@@ -663,14 +726,32 @@
 	uc->uc_credoff = UCRED_CRED_OFF;
 	uc->uc_privoff = UCRED_PRIV_OFF;
 	uc->uc_audoff = UCRED_AUD_OFF;
+	uc->uc_labeloff = UCRED_LABEL_OFF;
 	uc->uc_pid = pid;
 	uc->uc_projid = cr->cr_projid;
 	uc->uc_zoneid = crgetzoneid(cr);
 
-	cred2prcred(cr, UCCRED(uc));
-	cred2prpriv(cr, UCPRIV(uc));
-	if (audoff == 0 || cred2ucaud(cr, UCAUD(uc)) != 0)
+	/*
+	 * Note that cred2uclabel() call should not be factored out
+	 * to the bottom of the if-else. UCXXX() macros depend on
+	 * uc_xxxoff values to work correctly.
+	 */
+	if (REMOTE_PEER_CRED(cr)) {
+		/*
+		 * other than label, the rest of cred info about a
+		 * remote peer isn't available.
+		 */
+		cred2uclabel(cr, UCLABEL(uc));
+		uc->uc_credoff = 0;
+		uc->uc_privoff = 0;
 		uc->uc_audoff = 0;
+	} else {
+		cred2prcred(cr, UCCRED(uc));
+		cred2prpriv(cr, UCPRIV(uc));
+		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
+			uc->uc_audoff = 0;
+		cred2uclabel(cr, UCLABEL(uc));
+	}
 
 	return (uc);
 }
@@ -689,7 +770,7 @@
 	crhold(cr);
 	mutex_exit(&p->p_crlock);
 
-	uc = cred2ucred(cr, p->p_pid, NULL);
+	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
 	crfree(cr);
 
 	return (uc);
@@ -762,3 +843,64 @@
 	if (oldzptr)
 		zone_cred_rele(oldzptr);
 }
+
+/*
+ * 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 = kmem_cache_alloc(cred_cache, flags)) != NULL) {
+			bcopy(dummycr, cr, crsize);
+			cr->cr_label = lbl;
+		} else {
+			label_rele(lbl);
+		}
+	}
+
+	return (cr);
+}
+
+/*
+ * 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_bslabel(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) {
+		if ((newcr = kmem_cache_alloc(cred_cache, flags)) != NULL) {
+			bcopy(cr, newcr, crsize);
+			if (newcr->cr_zone)
+				zone_cred_hold(newcr->cr_zone);
+			newcr->cr_label = lbl;
+			newcr->cr_ref = 1;
+		} else {
+			label_rele(lbl);
+		}
+	}
+
+	return (newcr);
+}
+
+/*
+ * This function returns a pointer to the kcred-equivalent in the current zone.
+ */
+cred_t *
+zone_kcred(void)
+{
+	zone_t *zone;
+
+	if ((zone = CRED()->cr_zone) != NULL)
+		return (zone->zone_kcred);
+	else
+		return (kcred);
+}
--- a/usr/src/uts/common/os/exec.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/exec.c	Fri Mar 24 12:29:20 2006 -0800
@@ -78,6 +78,7 @@
 #define	PRIV_SETID		0x02	/* needs to change uids */
 #define	PRIV_SETUGID		0x04	/* is setuid/setgid/forced privs */
 #define	PRIV_INCREASE		0x08	/* child runs with more privs */
+#define	MAC_FLAGS		0x10	/* need to adjust MAC flags */
 
 static int execsetid(struct vnode *, struct vattr *, uid_t *, uid_t *);
 static int hold_execsw(struct execsw *);
@@ -515,6 +516,12 @@
 			cred->cr_sgid = gid;
 		}
 
+		if (privflags & MAC_FLAGS) {
+			if (!(CR_FLAGS(cred) & NET_MAC_AWARE_INHERIT))
+				CR_FLAGS(cred) &= ~NET_MAC_AWARE;
+			CR_FLAGS(cred) &= ~NET_MAC_AWARE_INHERIT;
+		}
+
 		/*
 		 * Implement the privilege updates:
 		 *
@@ -831,6 +838,11 @@
 	    !priv_isequalset(&CR_PPRIV(cr), &CR_IPRIV(cr)))
 		privflags |= PRIV_RESET;
 
+	/* If MAC-aware flag(s) are on, need to update cred to remove. */
+	if ((CR_FLAGS(cr) & NET_MAC_AWARE) ||
+	    (CR_FLAGS(cr) & NET_MAC_AWARE_INHERIT))
+		privflags |= MAC_FLAGS;
+
 	/*
 	 * When we introduce the "forced" set then we will need
 	 * to set PRIV_INCREASE here if I not a subset of P.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/os/labelsys.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,1384 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/kmem.h>
+#include <sys/strsubr.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/param.h>
+#include <sys/model.h>
+#include <sys/errno.h>
+#include <sys/modhash.h>
+
+#include <sys/policy.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tsyscall.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tnet.h>
+#include <sys/disp.h>
+
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <sys/sdt.h>
+
+static mod_hash_t *tpc_name_hash;	/* hash of cache entries by name */
+static kmutex_t tpc_lock;
+
+static tsol_tpc_t *tpc_unlab;
+
+/*
+ * tnrhc_table and tnrhc_table_v6 are similar to the IP forwarding tables
+ * in organization and search. The tnrhc_table[_v6] is an array of 33/129
+ * pointers to the 33/129 tnrhc tables indexed by the prefix length.
+ * A largest prefix match search is done by find_rhc_v[46] and it walks the
+ * tables from the most specific to the least specific table. Table 0
+ * corresponds to the single entry for 0.0.0.0/0 or ::0/0.
+ */
+tnrhc_hash_t *tnrhc_table[TSOL_MASK_TABLE_SIZE];
+tnrhc_hash_t *tnrhc_table_v6[TSOL_MASK_TABLE_SIZE_V6];
+kmutex_t tnrhc_g_lock;
+
+static void tsol_create_i_tmpls(void);
+
+static void tsol_create_i_tnrh(const tnaddr_t *);
+
+/* List of MLPs on valid on shared addresses */
+static tsol_mlp_list_t shared_mlps;
+
+/*
+ * Convert length for a mask to the mask.
+ */
+static ipaddr_t
+tsol_plen_to_mask(uint_t masklen)
+{
+	return (masklen == 0 ? 0 : htonl(IP_HOST_MASK << (IP_ABITS - masklen)));
+}
+
+/*
+ * Convert a prefix length to the mask for that prefix.
+ * Returns the argument bitmask.
+ */
+static void
+tsol_plen_to_mask_v6(uint_t plen, in6_addr_t *bitmask)
+{
+	uint32_t *ptr;
+
+	ASSERT(plen <= IPV6_ABITS);
+
+	ptr = (uint32_t *)bitmask;
+	while (plen >= 32) {
+		*ptr++ = 0xffffffffU;
+		plen -= 32;
+	}
+	if (plen > 0)
+		*ptr++ = htonl(0xffffffff << (32 - plen));
+	while (ptr < (uint32_t *)(bitmask + 1))
+		*ptr++ = 0;
+}
+
+boolean_t
+tnrhc_init_table(tnrhc_hash_t *table[], short prefix_len, int kmflag)
+{
+	int	i;
+
+	mutex_enter(&tnrhc_g_lock);
+
+	if (table[prefix_len] == NULL) {
+		table[prefix_len] = (tnrhc_hash_t *)
+		    kmem_zalloc(TNRHC_SIZE * sizeof (tnrhc_hash_t), kmflag);
+		if (table[prefix_len] == NULL) {
+			mutex_exit(&tnrhc_g_lock);
+			return (B_FALSE);
+		}
+		for (i = 0; i < TNRHC_SIZE; i++) {
+			mutex_init(&table[prefix_len][i].tnrh_lock,
+			    NULL, MUTEX_DEFAULT, 0);
+		}
+	}
+	mutex_exit(&tnrhc_g_lock);
+	return (B_TRUE);
+}
+
+void
+tcache_init(void)
+{
+	tnaddr_t address;
+
+	/*
+	 * Note: unable to use mod_hash_create_strhash here, since it's
+	 * assymetric.  It assumes that the user has allocated exactly
+	 * strlen(key) + 1 bytes for the key when inserted, and attempts to
+	 * kmem_free that memory on a delete.
+	 */
+	tpc_name_hash = mod_hash_create_extended("tnrhtpc_by_name", 256,
+	    mod_hash_null_keydtor,  mod_hash_null_valdtor, mod_hash_bystr,
+	    NULL, mod_hash_strkey_cmp, KM_SLEEP);
+	mutex_init(&tpc_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	mutex_init(&tnrhc_g_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	/* label_init always called before tcache_init */
+	ASSERT(l_admin_low != NULL && l_admin_high != NULL);
+
+	/* Initialize the zeroth table prior to loading the 0.0.0.0 entry */
+	(void) tnrhc_init_table(tnrhc_table, 0, KM_SLEEP);
+	(void) tnrhc_init_table(tnrhc_table_v6, 0, KM_SLEEP);
+	/*
+	 * create an internal host template called "_unlab"
+	 */
+	tsol_create_i_tmpls();
+
+	/*
+	 * create a host entry, 0.0.0.0 = _unlab
+	 */
+	bzero(&address, sizeof (tnaddr_t));
+	address.ta_family = AF_INET;
+	tsol_create_i_tnrh(&address);
+
+	/*
+	 * create a host entry, ::0 = _unlab
+	 */
+	address.ta_family = AF_INET6;
+	tsol_create_i_tnrh(&address);
+
+	rw_init(&shared_mlps.mlpl_rwlock, NULL, RW_DEFAULT, NULL);
+}
+
+/* Called only by the TNRHC_RELE macro when the refcount goes to zero. */
+void
+tnrhc_free(tsol_tnrhc_t *tnrhc)
+{
+	/*
+	 * We assert rhc_invalid here to make sure that no new thread could
+	 * possibly end up finding this entry.  If it could, then the
+	 * mutex_destroy would panic.
+	 */
+	DTRACE_PROBE1(tx__tndb__l3__tnrhcfree, tsol_tnrhc_t *, tnrhc);
+	ASSERT(tnrhc->rhc_next == NULL && tnrhc->rhc_invalid);
+	mutex_exit(&tnrhc->rhc_lock);
+	mutex_destroy(&tnrhc->rhc_lock);
+	if (tnrhc->rhc_tpc != NULL)
+		TPC_RELE(tnrhc->rhc_tpc);
+	kmem_free(tnrhc, sizeof (*tnrhc));
+}
+
+/* Called only by the TPC_RELE macro when the refcount goes to zero. */
+void
+tpc_free(tsol_tpc_t *tpc)
+{
+	DTRACE_PROBE1(tx__tndb__l3__tpcfree, tsol_tpc_t *, tpc);
+	ASSERT(tpc->tpc_invalid);
+	mutex_exit(&tpc->tpc_lock);
+	mutex_destroy(&tpc->tpc_lock);
+	kmem_free(tpc, sizeof (*tpc));
+}
+
+/*
+ * Find and hold a reference to a template entry by name.  Ignores entries that
+ * are being deleted.
+ */
+static tsol_tpc_t *
+tnrhtp_find(const char *name, mod_hash_t *hash)
+{
+	mod_hash_val_t hv;
+	tsol_tpc_t *tpc = NULL;
+
+	mutex_enter(&tpc_lock);
+	if (mod_hash_find(hash, (mod_hash_key_t)name, &hv) == 0) {
+		tpc = (tsol_tpc_t *)hv;
+		if (tpc->tpc_invalid)
+			tpc = NULL;
+		else
+			TPC_HOLD(tpc);
+	}
+	mutex_exit(&tpc_lock);
+	return (tpc);
+}
+
+static int
+tnrh_delete(const tsol_rhent_t *rhent)
+{
+	tsol_tnrhc_t *current;
+	tsol_tnrhc_t **prevp;
+	ipaddr_t tmpmask;
+	in6_addr_t tmpmask_v6;
+	tnrhc_hash_t *tnrhc_hash;
+
+	if (rhent->rh_address.ta_family == AF_INET) {
+		if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS)
+			return (EINVAL);
+		if (tnrhc_table[rhent->rh_prefix] == NULL)
+			return (ENOENT);
+		tmpmask = tsol_plen_to_mask(rhent->rh_prefix);
+		tnrhc_hash = &tnrhc_table[rhent->rh_prefix][
+		    TSOL_ADDR_HASH(rhent->rh_address.ta_addr_v4.s_addr &
+		    tmpmask, TNRHC_SIZE)];
+	} else if (rhent->rh_address.ta_family == AF_INET6) {
+		if (rhent->rh_prefix < 0 || rhent->rh_prefix > IPV6_ABITS)
+			return (EINVAL);
+		if (tnrhc_table_v6[rhent->rh_prefix] == NULL)
+			return (ENOENT);
+		tsol_plen_to_mask_v6(rhent->rh_prefix, &tmpmask_v6);
+		tnrhc_hash = &tnrhc_table_v6[rhent->rh_prefix][
+		    TSOL_ADDR_MASK_HASH_V6(rhent->rh_address.ta_addr_v6,
+		    tmpmask_v6, TNRHC_SIZE)];
+	} else {
+		return (EAFNOSUPPORT);
+	}
+
+	/* search for existing entry */
+	mutex_enter(&tnrhc_hash->tnrh_lock);
+	prevp = &tnrhc_hash->tnrh_list;
+	while ((current = *prevp) != NULL) {
+		if (TNADDR_EQ(&rhent->rh_address, &current->rhc_host))
+			break;
+		prevp = &current->rhc_next;
+	}
+
+	if (current != NULL) {
+		DTRACE_PROBE(tx__tndb__l2__tnrhdelete_existingrhentry);
+		*prevp = current->rhc_next;
+		mutex_enter(&current->rhc_lock);
+		current->rhc_next = NULL;
+		current->rhc_invalid = 1;
+		mutex_exit(&current->rhc_lock);
+		TNRHC_RELE(current);
+	}
+	mutex_exit(&tnrhc_hash->tnrh_lock);
+	return (current == NULL ? ENOENT : 0);
+}
+
+/*
+ * Flush all remote host entries from the database.
+ *
+ * Note that the htable arrays themselves do not have reference counters, so,
+ * unlike the remote host entries, they cannot be freed.
+ */
+static void
+flush_rh_table(tnrhc_hash_t **htable, int nbits)
+{
+	tnrhc_hash_t *hent, *hend;
+	tsol_tnrhc_t *rhc, *rhnext;
+
+	while (--nbits >= 0) {
+		if ((hent = htable[nbits]) == NULL)
+			continue;
+		hend = hent + TNRHC_SIZE;
+		while (hent < hend) {
+			/*
+			 * List walkers hold this lock during the walk.  It
+			 * protects tnrh_list and rhc_next.
+			 */
+			mutex_enter(&hent->tnrh_lock);
+			rhnext = hent->tnrh_list;
+			hent->tnrh_list = NULL;
+			mutex_exit(&hent->tnrh_lock);
+			/*
+			 * There may still be users of the rhcs at this point,
+			 * but not of the list or its next pointer.  Thus, the
+			 * only thing that would need to be done under a lock
+			 * is setting the invalid bit, but that's atomic
+			 * anyway, so no locks needed here.
+			 */
+			while ((rhc = rhnext) != NULL) {
+				rhnext = rhc->rhc_next;
+				rhc->rhc_next = NULL;
+				rhc->rhc_invalid = 1;
+				TNRHC_RELE(rhc);
+			}
+			hent++;
+		}
+	}
+}
+
+/*
+ * Load a remote host entry into kernel cache.  Create a new one if a matching
+ * entry isn't found, otherwise replace the contents of the previous one by
+ * deleting it and recreating it.  (Delete and recreate is used to avoid
+ * allowing other threads to see an unstable data structure.)
+ *
+ * A "matching" entry is the one whose address matches that of the one
+ * being loaded.
+ *
+ * Return 0 for success, error code for failure.
+ */
+int
+tnrh_load(const tsol_rhent_t *rhent)
+{
+	tsol_tnrhc_t **rhp;
+	tsol_tnrhc_t *rh, *new;
+	tsol_tpc_t *tpc;
+	ipaddr_t tmpmask;
+	in6_addr_t tmpmask_v6;
+	tnrhc_hash_t *tnrhc_hash;
+
+	/* Find the existing entry, if any, leaving the hash locked */
+	if (rhent->rh_address.ta_family == AF_INET) {
+		if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS)
+			return (EINVAL);
+		if (tnrhc_table[rhent->rh_prefix] == NULL &&
+		    !tnrhc_init_table(tnrhc_table, rhent->rh_prefix,
+		    KM_NOSLEEP))
+			return (ENOMEM);
+		tmpmask = tsol_plen_to_mask(rhent->rh_prefix);
+		tnrhc_hash = &tnrhc_table[rhent->rh_prefix][
+		    TSOL_ADDR_HASH(rhent->rh_address.ta_addr_v4.s_addr &
+		    tmpmask, TNRHC_SIZE)];
+		mutex_enter(&tnrhc_hash->tnrh_lock);
+		for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL;
+		    rhp = &rh->rhc_next) {
+			ASSERT(rh->rhc_host.ta_family == AF_INET);
+			if (((rh->rhc_host.ta_addr_v4.s_addr ^
+			    rhent->rh_address.ta_addr_v4.s_addr) & tmpmask) ==
+			    0)
+				break;
+		}
+	} else if (rhent->rh_address.ta_family == AF_INET6) {
+		if (rhent->rh_prefix < 0 || rhent->rh_prefix > IPV6_ABITS)
+			return (EINVAL);
+		if (tnrhc_table_v6[rhent->rh_prefix] == NULL &&
+		    !tnrhc_init_table(tnrhc_table_v6, rhent->rh_prefix,
+		    KM_NOSLEEP))
+			return (ENOMEM);
+		tsol_plen_to_mask_v6(rhent->rh_prefix, &tmpmask_v6);
+		tnrhc_hash = &tnrhc_table_v6[rhent->rh_prefix][
+		    TSOL_ADDR_MASK_HASH_V6(rhent->rh_address.ta_addr_v6,
+		    tmpmask_v6, TNRHC_SIZE)];
+		mutex_enter(&tnrhc_hash->tnrh_lock);
+		for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL;
+		    rhp = &rh->rhc_next) {
+			ASSERT(rh->rhc_host.ta_family == AF_INET6);
+			if (V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask_v6,
+			    rhent->rh_address.ta_addr_v6))
+				break;
+		}
+	} else {
+		return (EAFNOSUPPORT);
+	}
+
+	if ((new = kmem_zalloc(sizeof (*new), KM_NOSLEEP)) == NULL) {
+		mutex_exit(&tnrhc_hash->tnrh_lock);
+		return (ENOMEM);
+	}
+
+	/* Find and bump the reference count on the named template */
+	if ((tpc = tnrhtp_find(rhent->rh_template, tpc_name_hash)) == NULL) {
+		mutex_exit(&tnrhc_hash->tnrh_lock);
+		kmem_free(new, sizeof (*new));
+		return (EINVAL);
+	}
+
+	/* Clobber the old remote host entry. */
+	if (rh != NULL) {
+		ASSERT(!rh->rhc_invalid);
+		rh->rhc_invalid = 1;
+		*rhp = rh->rhc_next;
+		rh->rhc_next = NULL;
+		TNRHC_RELE(rh);
+	}
+
+	/* Initialize the new entry. */
+	mutex_init(&new->rhc_lock, NULL, MUTEX_DEFAULT, NULL);
+	new->rhc_host = rhent->rh_address;
+
+	/* The rhc now owns this tpc reference, so no TPC_RELE past here */
+	new->rhc_tpc = tpc;
+
+	ASSERT(tpc->tpc_tp.host_type == UNLABELED ||
+	    tpc->tpc_tp.host_type == SUN_CIPSO);
+
+	TNRHC_HOLD(new);
+	new->rhc_next = tnrhc_hash->tnrh_list;
+	tnrhc_hash->tnrh_list = new;
+	DTRACE_PROBE(tx__tndb__l2__tnrhload__addedrh);
+	mutex_exit(&tnrhc_hash->tnrh_lock);
+
+	return (0);
+}
+
+static int
+tnrh_get(tsol_rhent_t *rhent)
+{
+	tsol_tpc_t *tpc;
+
+	switch (rhent->rh_address.ta_family) {
+	case AF_INET:
+		tpc = find_tpc(&rhent->rh_address.ta_addr_v4, IPV4_VERSION,
+		    B_TRUE);
+		break;
+
+	case AF_INET6:
+		tpc = find_tpc(&rhent->rh_address.ta_addr_v6, IPV6_VERSION,
+		    B_TRUE);
+		break;
+
+	default:
+		return (EINVAL);
+	}
+	if (tpc == NULL)
+		return (ENOENT);
+
+	DTRACE_PROBE2(tx__tndb__l4__tnrhget__foundtpc, tsol_rhent_t *,
+	    rhent, tsol_tpc_t *, tpc);
+	bcopy(tpc->tpc_tp.name, rhent->rh_template,
+	    sizeof (rhent->rh_template));
+	TPC_RELE(tpc);
+	return (0);
+}
+
+static boolean_t
+template_name_ok(const char *name)
+{
+	const char *name_end = name + TNTNAMSIZ;
+
+	while (name < name_end) {
+		if (*name == '\0')
+			break;
+		name++;
+	}
+	return (name < name_end);
+}
+
+static int
+tnrh(int cmd, void *buf)
+{
+	int retv;
+	tsol_rhent_t rhent;
+
+	/* Make sure user has sufficient privilege */
+	if (cmd != TNDB_GET &&
+	    (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0)
+		return (set_errno(retv));
+
+	/*
+	 * Get arguments
+	 */
+	if (cmd != TNDB_FLUSH &&
+	    copyin(buf, &rhent, sizeof (rhent)) != 0) {
+		DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyin);
+		return (set_errno(EFAULT));
+	}
+
+	switch (cmd) {
+	case TNDB_LOAD:
+		DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbload);
+		if (!template_name_ok(rhent.rh_template)) {
+			retv = EINVAL;
+		} else {
+			retv = tnrh_load(&rhent);
+		}
+		break;
+
+	case TNDB_DELETE:
+		DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbdelete);
+		retv = tnrh_delete(&rhent);
+		break;
+
+	case TNDB_GET:
+		DTRACE_PROBE(tx__tndb__l4__tnrhdelete__tndbget);
+		if (!template_name_ok(rhent.rh_template)) {
+			retv = EINVAL;
+			break;
+		}
+
+		retv = tnrh_get(&rhent);
+		if (retv != 0)
+			break;
+
+		/*
+		 * Copy out result
+		 */
+		if (copyout(&rhent, buf, sizeof (rhent)) != 0) {
+			DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyout);
+			retv = EFAULT;
+		}
+		break;
+
+	case TNDB_FLUSH:
+		DTRACE_PROBE(tx__tndb__l2__tnrhdelete__flush);
+		flush_rh_table(tnrhc_table, TSOL_MASK_TABLE_SIZE);
+		flush_rh_table(tnrhc_table_v6, TSOL_MASK_TABLE_SIZE_V6);
+		break;
+
+	default:
+		DTRACE_PROBE1(tx__tndb__l0__tnrhdelete__unknowncmd,
+		    int, cmd);
+		retv = EOPNOTSUPP;
+		break;
+	}
+
+	if (retv != 0)
+		return (set_errno(retv));
+	else
+		return (retv);
+}
+
+static tsol_tpc_t *
+tnrhtp_create(const tsol_tpent_t *tpent, int kmflags)
+{
+	tsol_tpc_t *tpc;
+	mod_hash_val_t hv;
+
+	/*
+	 * We intentionally allocate a new entry before taking the lock on the
+	 * entire database.
+	 */
+	if ((tpc = kmem_zalloc(sizeof (*tpc), kmflags)) == NULL)
+		return (NULL);
+
+	mutex_enter(&tpc_lock);
+	if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tpent->name,
+	    &hv) == 0) {
+		tsol_tpc_t *found_tpc = (tsol_tpc_t *)hv;
+
+		found_tpc->tpc_invalid = 1;
+		(void) mod_hash_destroy(tpc_name_hash,
+		    (mod_hash_key_t)tpent->name);
+		TPC_RELE(found_tpc);
+	}
+
+	mutex_init(&tpc->tpc_lock, NULL, MUTEX_DEFAULT, NULL);
+	/* tsol_tpent_t is the same on LP64 and ILP32 */
+	bcopy(tpent, &tpc->tpc_tp, sizeof (tpc->tpc_tp));
+	(void) mod_hash_insert(tpc_name_hash, (mod_hash_key_t)tpc->tpc_tp.name,
+	    (mod_hash_val_t)tpc);
+	TPC_HOLD(tpc);
+	mutex_exit(&tpc_lock);
+
+	return (tpc);
+}
+
+static int
+tnrhtp_delete(const char *tname)
+{
+	tsol_tpc_t *tpc;
+	mod_hash_val_t hv;
+	int retv = ENOENT;
+
+	mutex_enter(&tpc_lock);
+	if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tname, &hv) == 0) {
+		tpc = (tsol_tpc_t *)hv;
+		ASSERT(!tpc->tpc_invalid);
+		tpc->tpc_invalid = 1;
+		(void) mod_hash_destroy(tpc_name_hash,
+		    (mod_hash_key_t)tpc->tpc_tp.name);
+		TPC_RELE(tpc);
+		retv = 0;
+	}
+	mutex_exit(&tpc_lock);
+	return (retv);
+}
+
+/* ARGSUSED */
+static uint_t
+tpc_delete(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+	tsol_tpc_t *tpc = (tsol_tpc_t *)val;
+
+	ASSERT(!tpc->tpc_invalid);
+	tpc->tpc_invalid = 1;
+	TPC_RELE(tpc);
+	return (MH_WALK_CONTINUE);
+}
+
+static void
+tnrhtp_flush(void)
+{
+	mutex_enter(&tpc_lock);
+	mod_hash_walk(tpc_name_hash, tpc_delete, NULL);
+	mod_hash_clear(tpc_name_hash);
+	mutex_exit(&tpc_lock);
+}
+
+static int
+tnrhtp(int cmd, void *buf)
+{
+	int retv;
+	int type;
+	tsol_tpent_t rhtpent;
+	tsol_tpc_t *tpc;
+
+	/* Make sure user has sufficient privilege */
+	if (cmd != TNDB_GET &&
+	    (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0)
+		return (set_errno(retv));
+
+	/*
+	 * Get argument.  Note that tsol_tpent_t is the same on LP64 and ILP32,
+	 * so no special handling is required.
+	 */
+	if (cmd != TNDB_FLUSH) {
+		if (copyin(buf, &rhtpent, sizeof (rhtpent)) != 0) {
+			DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyin);
+			return (set_errno(EFAULT));
+		}
+
+		/*
+		 * Don't let the user give us a bogus (unterminated) template
+		 * name.
+		 */
+		if (!template_name_ok(rhtpent.name))
+			return (set_errno(EINVAL));
+	}
+
+	switch (cmd) {
+	case TNDB_LOAD:
+		DTRACE_PROBE1(tx__tndb__l2__tnrhtp__tndbload, char *,
+			rhtpent.name);
+		type = rhtpent.host_type;
+		if (type != UNLABELED && type != SUN_CIPSO) {
+			retv = EINVAL;
+			break;
+		}
+
+		if (tnrhtp_create(&rhtpent, KM_NOSLEEP) == NULL)
+			retv = ENOMEM;
+		else
+			retv = 0;
+		break;
+
+	case TNDB_GET:
+		DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbget, char *,
+		    rhtpent.name);
+		tpc = tnrhtp_find(rhtpent.name, tpc_name_hash);
+		if (tpc == NULL) {
+			retv = ENOENT;
+			break;
+		}
+
+		/* Copy out result */
+		if (copyout(&tpc->tpc_tp, buf, sizeof (tpc->tpc_tp)) != 0) {
+			DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyout);
+			retv = EFAULT;
+		} else {
+			retv = 0;
+		}
+		TPC_RELE(tpc);
+		break;
+
+	case TNDB_DELETE:
+		DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbdelete, char *,
+		    rhtpent.name);
+		retv = tnrhtp_delete(rhtpent.name);
+		break;
+
+	case TNDB_FLUSH:
+		DTRACE_PROBE(tx__tndb__l4__tnrhtp__flush);
+		tnrhtp_flush();
+		retv = 0;
+		break;
+
+	default:
+		DTRACE_PROBE1(tx__tndb__l0__tnrhtp__unknowncmd, int,
+		    cmd);
+		retv = EOPNOTSUPP;
+		break;
+	}
+
+	if (retv != 0)
+		return (set_errno(retv));
+	else
+		return (retv);
+}
+
+/*
+ * MLP entry ordering logic
+ *
+ * There are two loops in this routine.  The first loop finds the entry that
+ * either logically follows the new entry to be inserted, or is the entry that
+ * precedes and overlaps the new entry, or is NULL to mean end-of-list.  This
+ * is 'tme.'  The second loop scans ahead from that point to find any overlap
+ * on the front or back of this new entry.
+ *
+ * For the first loop, we can have the following cases in the list (note that
+ * the port-portmax range is inclusive):
+ *
+ *	       port   portmax
+ *		+--------+
+ * 1: +------+ ................... precedes; skip to next
+ * 2:	    +------+ ............. overlaps; stop here if same protocol
+ * 3:		+------+ ......... overlaps; stop if same or higher protocol
+ * 4:		    +-------+ .... overlaps or succeeds; stop here
+ *
+ * For the second loop, we can have the following cases (note that we need not
+ * care about other protocol entries at this point, because we're only looking
+ * for overlap, not an insertion point):
+ *
+ *	       port   portmax
+ *		+--------+
+ * 5:	    +------+ ............. overlaps; stop if same protocol
+ * 6:		+------+ ......... overlaps; stop if same protocol
+ * 7:		    +-------+ .... overlaps; stop if same protocol
+ * 8:			   +---+ . follows; search is done
+ *
+ * In other words, this second search needs to consider only whether the entry
+ * has a starting port number that's greater than the end point of the new
+ * entry.  All others are overlaps.
+ */
+static int
+mlp_add_del(tsol_mlp_list_t *mlpl, zoneid_t zoneid, uint8_t proto,
+    uint16_t port, uint16_t portmax, boolean_t addflag)
+{
+	int retv;
+	tsol_mlp_entry_t *tme, *tme2, *newent;
+
+	if (addflag) {
+		if ((newent = kmem_zalloc(sizeof (*newent), KM_NOSLEEP)) ==
+		    NULL)
+			return (ENOMEM);
+	} else {
+		newent = NULL;
+	}
+	rw_enter(&mlpl->mlpl_rwlock, RW_WRITER);
+
+	/*
+	 * First loop: find logical insertion point or overlap.  Table is kept
+	 * in order of port number first, and then, within that, by protocol
+	 * number.
+	 */
+	for (tme = mlpl->mlpl_first; tme != NULL; tme = tme->mlpe_next) {
+		/* logically next (case 4) */
+		if (tme->mlpe_mlp.mlp_port > port)
+			break;
+		/* if this is logically next or overlap, then stop (case 3) */
+		if (tme->mlpe_mlp.mlp_port == port &&
+		    tme->mlpe_mlp.mlp_ipp >= proto)
+			break;
+		/* earlier or same port sequence; check for overlap (case 2) */
+		if (tme->mlpe_mlp.mlp_ipp == proto &&
+		    tme->mlpe_mlp.mlp_port_upper >= port)
+			break;
+		/* otherwise, loop again (case 1) */
+	}
+
+	/* Second loop: scan ahead for overlap */
+	for (tme2 = tme; tme2 != NULL; tme2 = tme2->mlpe_next) {
+		/* check if entry follows; no overlap (case 8) */
+		if (tme2->mlpe_mlp.mlp_port > portmax) {
+			tme2 = NULL;
+			break;
+		}
+		/* only exact protocol matches at this point (cases 5-7) */
+		if (tme2->mlpe_mlp.mlp_ipp == proto)
+			break;
+	}
+
+	retv = 0;
+	if (addflag) {
+		if (tme2 != NULL) {
+			retv = EEXIST;
+		} else {
+			newent->mlpe_zoneid = zoneid;
+			newent->mlpe_mlp.mlp_ipp = proto;
+			newent->mlpe_mlp.mlp_port = port;
+			newent->mlpe_mlp.mlp_port_upper = portmax;
+			newent->mlpe_next = tme;
+			if (tme == NULL) {
+				tme2 = mlpl->mlpl_last;
+				mlpl->mlpl_last = newent;
+			} else {
+				tme2 = tme->mlpe_prev;
+				tme->mlpe_prev = newent;
+			}
+			newent->mlpe_prev = tme2;
+			if (tme2 == NULL)
+				mlpl->mlpl_first = newent;
+			else
+				tme2->mlpe_next = newent;
+			newent = NULL;
+		}
+	} else {
+		if (tme2 == NULL || tme2->mlpe_mlp.mlp_port != port ||
+		    tme2->mlpe_mlp.mlp_port_upper != portmax) {
+			retv = ENOENT;
+		} else {
+			if ((tme2 = tme->mlpe_prev) == NULL)
+				mlpl->mlpl_first = tme->mlpe_next;
+			else
+				tme2->mlpe_next = tme->mlpe_next;
+			if ((tme2 = tme->mlpe_next) == NULL)
+				mlpl->mlpl_last = tme->mlpe_prev;
+			else
+				tme2->mlpe_prev = tme->mlpe_prev;
+			newent = tme;
+		}
+	}
+	rw_exit(&mlpl->mlpl_rwlock);
+
+	if (newent != NULL)
+		kmem_free(newent, sizeof (*newent));
+
+	return (retv);
+}
+
+/*
+ * Add or remove an MLP entry from the database so that the classifier can find
+ * it.
+ *
+ * Note: port number is in host byte order.
+ */
+int
+tsol_mlp_anon(zone_t *zone, mlp_type_t mlptype, uchar_t proto, uint16_t port,
+    boolean_t addflag)
+{
+	int retv = 0;
+
+	if (mlptype == mlptBoth || mlptype == mlptPrivate)
+		retv = mlp_add_del(&zone->zone_mlps, zone->zone_id, proto,
+		    port, port, addflag);
+	if ((retv == 0 || !addflag) &&
+	    (mlptype == mlptBoth || mlptype == mlptShared)) {
+		retv = mlp_add_del(&shared_mlps, zone->zone_id, proto, port,
+		    port, addflag);
+		if (retv != 0 && addflag)
+			(void) mlp_add_del(&zone->zone_mlps, zone->zone_id,
+			    proto, port, port, B_FALSE);
+	}
+	return (retv);
+}
+
+static void
+mlp_flush(tsol_mlp_list_t *mlpl, zoneid_t zoneid)
+{
+	tsol_mlp_entry_t *tme, *tme2, *tmnext;
+
+	rw_enter(&mlpl->mlpl_rwlock, RW_WRITER);
+	for (tme = mlpl->mlpl_first; tme != NULL; tme = tmnext) {
+		tmnext = tme->mlpe_next;
+		if (zoneid == ALL_ZONES || tme->mlpe_zoneid == zoneid) {
+			if ((tme2 = tme->mlpe_prev) == NULL)
+				mlpl->mlpl_first = tmnext;
+			else
+				tme2->mlpe_next = tmnext;
+			if (tmnext == NULL)
+				mlpl->mlpl_last = tme2;
+			else
+				tmnext->mlpe_prev = tme2;
+			kmem_free(tme, sizeof (*tme));
+		}
+	}
+	rw_exit(&mlpl->mlpl_rwlock);
+}
+
+/*
+ * Note: user supplies port numbers in host byte order.
+ */
+static int
+tnmlp(int cmd, void *buf)
+{
+	int retv;
+	tsol_mlpent_t tsme;
+	zone_t *zone;
+	tsol_mlp_list_t *mlpl;
+	tsol_mlp_entry_t *tme;
+
+	/* Make sure user has sufficient privilege */
+	if (cmd != TNDB_GET &&
+	    (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0)
+		return (set_errno(retv));
+
+	/*
+	 * Get argument.  Note that tsol_mlpent_t is the same on LP64 and
+	 * ILP32, so no special handling is required.
+	 */
+	if (copyin(buf, &tsme, sizeof (tsme)) != 0) {
+		DTRACE_PROBE(tx__tndb__l0__tnmlp__copyin);
+		return (set_errno(EFAULT));
+	}
+
+	/* MLPs on shared IP addresses */
+	if (tsme.tsme_flags & TSOL_MEF_SHARED) {
+		zone = NULL;
+		mlpl = &shared_mlps;
+	} else {
+		zone = zone_find_by_id(tsme.tsme_zoneid);
+		if (zone == NULL)
+			return (set_errno(EINVAL));
+		mlpl = &zone->zone_mlps;
+	}
+	if (tsme.tsme_mlp.mlp_port_upper == 0)
+		tsme.tsme_mlp.mlp_port_upper = tsme.tsme_mlp.mlp_port;
+
+	switch (cmd) {
+	case TNDB_LOAD:
+		DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbload,
+		    tsol_mlpent_t *, &tsme);
+		if (tsme.tsme_mlp.mlp_ipp == 0 || tsme.tsme_mlp.mlp_port == 0 ||
+		    tsme.tsme_mlp.mlp_port > tsme.tsme_mlp.mlp_port_upper) {
+			retv = EINVAL;
+			break;
+		}
+		retv = mlp_add_del(mlpl, tsme.tsme_zoneid,
+		    tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port,
+		    tsme.tsme_mlp.mlp_port_upper, B_TRUE);
+		break;
+
+	case TNDB_GET:
+		DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbget,
+		    tsol_mlpent_t *, &tsme);
+
+		/*
+		 * Search for the requested element or, failing that, the one
+		 * that's logically next in the sequence.
+		 */
+		rw_enter(&mlpl->mlpl_rwlock, RW_READER);
+		for (tme = mlpl->mlpl_first; tme != NULL;
+		    tme = tme->mlpe_next) {
+			if (tsme.tsme_zoneid != ALL_ZONES &&
+			    tme->mlpe_zoneid != tsme.tsme_zoneid)
+				continue;
+			if (tme->mlpe_mlp.mlp_ipp >= tsme.tsme_mlp.mlp_ipp &&
+			    tme->mlpe_mlp.mlp_port == tsme.tsme_mlp.mlp_port)
+				break;
+			if (tme->mlpe_mlp.mlp_port > tsme.tsme_mlp.mlp_port)
+				break;
+		}
+		if (tme == NULL) {
+			retv = ENOENT;
+		} else {
+			tsme.tsme_zoneid = tme->mlpe_zoneid;
+			tsme.tsme_mlp = tme->mlpe_mlp;
+			retv = 0;
+		}
+		rw_exit(&mlpl->mlpl_rwlock);
+		break;
+
+	case TNDB_DELETE:
+		DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbdelete,
+		    tsol_mlpent_t *, &tsme);
+		retv = mlp_add_del(mlpl, tsme.tsme_zoneid,
+		    tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port,
+		    tsme.tsme_mlp.mlp_port_upper, B_FALSE);
+		break;
+
+	case TNDB_FLUSH:
+		DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbflush,
+		    tsol_mlpent_t *, &tsme);
+		mlp_flush(mlpl, ALL_ZONES);
+		mlp_flush(&shared_mlps, tsme.tsme_zoneid);
+		retv = 0;
+		break;
+
+	default:
+		DTRACE_PROBE1(tx__tndb__l0__tnmlp__unknowncmd, int,
+		    cmd);
+		retv = EOPNOTSUPP;
+		break;
+	}
+
+	if (zone != NULL)
+		zone_rele(zone);
+
+	if (cmd == TNDB_GET && retv == 0) {
+		/* Copy out result */
+		if (copyout(&tsme, buf, sizeof (tsme)) != 0) {
+			DTRACE_PROBE(tx__tndb__l0__tnmlp__copyout);
+			retv = EFAULT;
+		}
+	}
+
+	if (retv != 0)
+		return (set_errno(retv));
+	else
+		return (retv);
+}
+
+/*
+ * Returns a tnrhc matching the addr address.
+ * The returned rhc's refcnt is incremented.
+ */
+tsol_tnrhc_t *
+find_rhc_v4(const in_addr_t *in4)
+{
+	tsol_tnrhc_t *rh = NULL;
+	tnrhc_hash_t *tnrhc_hash;
+	ipaddr_t tmpmask;
+	int	i;
+
+	for (i = (TSOL_MASK_TABLE_SIZE - 1); i >= 0; i--) {
+
+		if ((tnrhc_table[i]) == NULL)
+			continue;
+
+		tmpmask = tsol_plen_to_mask(i);
+		tnrhc_hash = &tnrhc_table[i][
+		    TSOL_ADDR_HASH(*in4 & tmpmask, TNRHC_SIZE)];
+
+		mutex_enter(&tnrhc_hash->tnrh_lock);
+		for (rh = tnrhc_hash->tnrh_list; rh != NULL;
+		    rh = rh->rhc_next) {
+			if ((rh->rhc_host.ta_family == AF_INET) &&
+			    ((rh->rhc_host.ta_addr_v4.s_addr & tmpmask) ==
+			    (*in4 & tmpmask))) {
+				TNRHC_HOLD(rh);
+				mutex_exit(&tnrhc_hash->tnrh_lock);
+				return (rh);
+			}
+		}
+		mutex_exit(&tnrhc_hash->tnrh_lock);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Returns a tnrhc matching the addr address.
+ * The returned rhc's refcnt is incremented.
+ */
+tsol_tnrhc_t *
+find_rhc_v6(const in6_addr_t *in6)
+{
+	tsol_tnrhc_t *rh = NULL;
+	tnrhc_hash_t *tnrhc_hash;
+	in6_addr_t tmpmask;
+	int i;
+
+	if (IN6_IS_ADDR_V4MAPPED(in6)) {
+		in_addr_t in4;
+
+		IN6_V4MAPPED_TO_IPADDR(in6, in4);
+		return (find_rhc_v4(&in4));
+	}
+
+	for (i = (TSOL_MASK_TABLE_SIZE_V6 - 1); i >= 0; i--) {
+		if ((tnrhc_table_v6[i]) == NULL)
+			continue;
+
+		tsol_plen_to_mask_v6(i, &tmpmask);
+		tnrhc_hash = &tnrhc_table_v6[i][
+		    TSOL_ADDR_MASK_HASH_V6(*in6, tmpmask, TNRHC_SIZE)];
+
+		mutex_enter(&tnrhc_hash->tnrh_lock);
+		for (rh = tnrhc_hash->tnrh_list; rh != NULL;
+		    rh = rh->rhc_next) {
+			if ((rh->rhc_host.ta_family == AF_INET6) &&
+			    V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask,
+			    *in6)) {
+				TNRHC_HOLD(rh);
+				mutex_exit(&tnrhc_hash->tnrh_lock);
+				return (rh);
+			}
+		}
+		mutex_exit(&tnrhc_hash->tnrh_lock);
+	}
+
+	return (NULL);
+}
+
+tsol_tpc_t *
+find_tpc(const void *addr, uchar_t version, boolean_t staleok)
+{
+	tsol_tpc_t *tpc;
+	tsol_tnrhc_t *rhc;
+
+	if (version == IPV4_VERSION)
+		rhc = find_rhc_v4(addr);
+	else
+		rhc = find_rhc_v6(addr);
+
+	if (rhc != NULL) {
+		tpc = rhc->rhc_tpc;
+		if (!staleok && tpc->tpc_invalid) {
+			/*
+			 * This should not happen unless the user deletes
+			 * templates without recreating them.  Try to find the
+			 * new version of template.  If there is none, then
+			 * just give up.
+			 */
+			tpc = tnrhtp_find(tpc->tpc_tp.name, tpc_name_hash);
+			if (tpc != NULL) {
+				TPC_RELE(rhc->rhc_tpc);
+				rhc->rhc_tpc = tpc;
+			}
+		}
+		if (tpc != NULL)
+			TPC_HOLD(tpc);
+		TNRHC_RELE(rhc);
+		return (tpc);
+	}
+	DTRACE_PROBE(tx__tndb__l1__findtpc__notemplate);
+	return (NULL);
+}
+
+/*
+ * create an internal template called "_unlab":
+ *
+ * _unlab;\
+ *	host_type = unlabeled;\
+ *	def_label = ADMIN_LOW[ADMIN_LOW];\
+ *	min_sl = ADMIN_LOW;\
+ *	max_sl = ADMIN_HIGH;
+ */
+static void
+tsol_create_i_tmpls(void)
+{
+	tsol_tpent_t rhtpent;
+
+	bzero(&rhtpent, sizeof (rhtpent));
+
+	/* create _unlab */
+	(void) strcpy(rhtpent.name, "_unlab");
+
+	rhtpent.host_type = UNLABELED;
+	rhtpent.tp_mask_unl = TSOL_MSK_DEF_LABEL | TSOL_MSK_DEF_CL |
+	    TSOL_MSK_SL_RANGE_TSOL;
+
+	rhtpent.tp_gw_sl_range.lower_bound = *label2bslabel(l_admin_low);
+	rhtpent.tp_def_label = rhtpent.tp_gw_sl_range.lower_bound;
+	rhtpent.tp_gw_sl_range.upper_bound = *label2bslabel(l_admin_high);
+	rhtpent.tp_cipso_doi_unl = default_doi;
+	tpc_unlab = tnrhtp_create(&rhtpent, KM_SLEEP);
+}
+
+/*
+ * set up internal host template, called from kernel only.
+ */
+static void
+tsol_create_i_tnrh(const tnaddr_t *sa)
+{
+	tsol_tnrhc_t *rh, *new;
+	tnrhc_hash_t *tnrhc_hash;
+
+	/* Allocate a new entry before taking the lock */
+	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
+
+	tnrhc_hash = (sa->ta_family == AF_INET) ? &tnrhc_table[0][0] :
+	    &tnrhc_table_v6[0][0];
+
+	mutex_enter(&tnrhc_hash->tnrh_lock);
+	rh = tnrhc_hash->tnrh_list;
+
+	if (rh == NULL) {
+		/* We're keeping the new entry. */
+		rh = new;
+		new = NULL;
+		rh->rhc_host = *sa;
+		mutex_init(&rh->rhc_lock, NULL, MUTEX_DEFAULT, NULL);
+		TNRHC_HOLD(rh);
+		tnrhc_hash->tnrh_list = rh;
+	}
+
+	/*
+	 * Link the entry to internal_unlab
+	 */
+	if (rh->rhc_tpc != tpc_unlab) {
+		if (rh->rhc_tpc != NULL)
+			TPC_RELE(rh->rhc_tpc);
+		rh->rhc_tpc = tpc_unlab;
+		TPC_HOLD(tpc_unlab);
+	}
+	mutex_exit(&tnrhc_hash->tnrh_lock);
+	if (new != NULL)
+		kmem_free(new, sizeof (*new));
+}
+
+/*
+ * Returns 0 if the port is known to be SLP.  Returns next possible port number
+ * (wrapping through 1) if port is MLP on shared or global.  Administrator
+ * should not make all ports MLP.  If that's done, then we'll just pretend
+ * everything is SLP to avoid looping forever.
+ *
+ * Note: port is in host byte order.
+ */
+in_port_t
+tsol_next_port(zone_t *zone, in_port_t port, int proto, boolean_t upward)
+{
+	boolean_t loop;
+	tsol_mlp_entry_t *tme;
+	int newport = port;
+
+	loop = B_FALSE;
+	for (;;) {
+		if (zone != NULL && zone->zone_mlps.mlpl_first != NULL) {
+			rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER);
+			for (tme = zone->zone_mlps.mlpl_first; tme != NULL;
+			    tme = tme->mlpe_next) {
+				if (proto == tme->mlpe_mlp.mlp_ipp &&
+				    newport >= tme->mlpe_mlp.mlp_port &&
+				    newport <= tme->mlpe_mlp.mlp_port_upper)
+					newport = upward ?
+					    tme->mlpe_mlp.mlp_port_upper + 1 :
+					    tme->mlpe_mlp.mlp_port - 1;
+			}
+			rw_exit(&zone->zone_mlps.mlpl_rwlock);
+		}
+		if (shared_mlps.mlpl_first != NULL) {
+			rw_enter(&shared_mlps.mlpl_rwlock, RW_READER);
+			for (tme = shared_mlps.mlpl_first; tme != NULL;
+			    tme = tme->mlpe_next) {
+				if (proto == tme->mlpe_mlp.mlp_ipp &&
+				    newport >= tme->mlpe_mlp.mlp_port &&
+				    newport <= tme->mlpe_mlp.mlp_port_upper)
+					newport = upward ?
+					    tme->mlpe_mlp.mlp_port_upper + 1 :
+					    tme->mlpe_mlp.mlp_port - 1;
+			}
+			rw_exit(&shared_mlps.mlpl_rwlock);
+		}
+		if (newport <= 65535 && newport > 0)
+			break;
+		if (loop)
+			return (0);
+		loop = B_TRUE;
+		newport = upward ? 1 : 65535;
+	}
+	return (newport == port ? 0 : newport);
+}
+
+/*
+ * tsol_mlp_port_type will check if the given (zone, proto, port) is a
+ * multilevel port.  If it is, return the type (shared, private, or both), or
+ * indicate that it's single-level.
+ *
+ * Note: port is given in host byte order, not network byte order.
+ */
+mlp_type_t
+tsol_mlp_port_type(zone_t *zone, uchar_t proto, uint16_t port,
+    mlp_type_t mlptype)
+{
+	tsol_mlp_entry_t *tme;
+
+	if (mlptype == mlptBoth || mlptype == mlptPrivate) {
+		tme = NULL;
+		if (zone->zone_mlps.mlpl_first != NULL) {
+			rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER);
+			for (tme = zone->zone_mlps.mlpl_first; tme != NULL;
+			    tme = tme->mlpe_next) {
+				if (proto == tme->mlpe_mlp.mlp_ipp &&
+				    port >= tme->mlpe_mlp.mlp_port &&
+				    port <= tme->mlpe_mlp.mlp_port_upper)
+					break;
+			}
+			rw_exit(&zone->zone_mlps.mlpl_rwlock);
+		}
+		if (tme == NULL) {
+			if (mlptype == mlptBoth)
+				mlptype = mlptShared;
+			else if (mlptype == mlptPrivate)
+				mlptype = mlptSingle;
+		}
+	}
+	if (mlptype == mlptBoth || mlptype == mlptShared) {
+		tme = NULL;
+		if (shared_mlps.mlpl_first != NULL) {
+			rw_enter(&shared_mlps.mlpl_rwlock, RW_READER);
+			for (tme = shared_mlps.mlpl_first; tme != NULL;
+			    tme = tme->mlpe_next) {
+				if (proto == tme->mlpe_mlp.mlp_ipp &&
+				    port >= tme->mlpe_mlp.mlp_port &&
+				    port <= tme->mlpe_mlp.mlp_port_upper)
+					break;
+			}
+			rw_exit(&shared_mlps.mlpl_rwlock);
+		}
+		if (tme == NULL) {
+			if (mlptype == mlptBoth)
+				mlptype = mlptPrivate;
+			else if (mlptype == mlptShared)
+				mlptype = mlptSingle;
+		}
+	}
+	return (mlptype);
+}
+
+/*
+ * tsol_mlp_findzone will check if the given (proto, port) is a multilevel port
+ * on a shared address.  If it is, return the owning zone.
+ *
+ * Note: lport is in network byte order, unlike the other MLP functions,
+ * because the callers of this function are all dealing with packets off the
+ * wire.
+ */
+zoneid_t
+tsol_mlp_findzone(uchar_t proto, uint16_t lport)
+{
+	tsol_mlp_entry_t *tme;
+	zoneid_t zoneid;
+	uint16_t port;
+
+	if (shared_mlps.mlpl_first == NULL)
+		return (ALL_ZONES);
+	port = ntohs(lport);
+	rw_enter(&shared_mlps.mlpl_rwlock, RW_READER);
+	for (tme = shared_mlps.mlpl_first; tme != NULL; tme = tme->mlpe_next) {
+		if (proto == tme->mlpe_mlp.mlp_ipp &&
+		    port >= tme->mlpe_mlp.mlp_port &&
+		    port <= tme->mlpe_mlp.mlp_port_upper)
+			break;
+	}
+	zoneid = tme == NULL ? ALL_ZONES : tme->mlpe_zoneid;
+	rw_exit(&shared_mlps.mlpl_rwlock);
+	return (zoneid);
+}
+
+/* Debug routine */
+void
+tsol_print_label(const blevel_t *blev, const char *name)
+{
+	const _blevel_impl_t *bli = (const _blevel_impl_t *)blev;
+
+	/* We really support only sensitivity labels */
+	cmn_err(CE_NOTE, "%s %x:%x:%08x%08x%08x%08x%08x%08x%08x%08x",
+	    name, bli->id, LCLASS(bli), ntohl(bli->_comps.c1),
+	    ntohl(bli->_comps.c2), ntohl(bli->_comps.c3), ntohl(bli->_comps.c4),
+	    ntohl(bli->_comps.c5), ntohl(bli->_comps.c6), ntohl(bli->_comps.c7),
+	    ntohl(bli->_comps.c8));
+}
+
+/*
+ * Name:	labelsys()
+ *
+ * Normal:	Routes TSOL syscalls.
+ *
+ * Output:	As defined for each TSOL syscall.
+ *		Returns ENOSYS for unrecognized calls.
+ */
+/* ARGSUSED */
+int
+labelsys(int op, void *a1, void *a2, void *a3, void *a4, void *a5)
+{
+	switch (op) {
+	case TSOL_SYSLABELING:
+		return (sys_labeling);
+	case TSOL_TNRH:
+		return (tnrh((int)(uintptr_t)a1, a2));
+	case TSOL_TNRHTP:
+		return (tnrhtp((int)(uintptr_t)a1, a2));
+	case TSOL_TNMLP:
+		return (tnmlp((int)(uintptr_t)a1, a2));
+	case TSOL_GETLABEL:
+		return (getlabel((char *)a1, (bslabel_t *)a2));
+	case TSOL_FGETLABEL:
+		return (fgetlabel((int)(uintptr_t)a1, (bslabel_t *)a2));
+	default:
+		return (set_errno(ENOSYS));
+	}
+	/* NOTREACHED */
+}
--- a/usr/src/uts/common/os/main.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/main.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,7 +44,6 @@
 #include <sys/file.h>
 #include <sys/priocntl.h>
 #include <sys/procset.h>
-#include <sys/var.h>
 #include <sys/disp.h>
 #include <sys/callo.h>
 #include <sys/callb.h>
--- a/usr/src/uts/common/os/policy.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/policy.c	Fri Mar 24 12:29:20 2006 -0800
@@ -39,7 +39,6 @@
 #include <sys/proc.h>
 #include <sys/acct.h>
 #include <sys/ipc_impl.h>
-#include <sys/syscall.h>
 #include <sys/cmn_err.h>
 #include <sys/debug.h>
 #include <sys/policy.h>
@@ -51,16 +50,12 @@
 #include <sys/modctl.h>
 #include <sys/disp.h>
 #include <sys/zone.h>
-#include <inet/common.h>
 #include <inet/optcom.h>
 #include <sys/sdt.h>
-#include <sys/mount.h>
 #include <sys/vfs.h>
 #include <sys/mntent.h>
 #include <sys/contract_impl.h>
 
-#include <sys/sunddi.h>
-
 /*
  * There are two possible layers of privilege routines and two possible
  * levels of secpolicy.  Plus one other we may not be interested in, so
@@ -503,6 +498,27 @@
 }
 
 /*
+ * Binding to a multilevel port on a trusted (labeled) system.
+ */
+int
+secpolicy_net_bindmlp(const cred_t *cr)
+{
+	return (PRIV_POLICY(cr, PRIV_NET_BINDMLP, B_FALSE, EACCES,
+	    NULL));
+}
+
+/*
+ * Allow a communication between a zone and an unlabeled host when their
+ * labels don't match.
+ */
+int
+secpolicy_net_mac_aware(const cred_t *cr)
+{
+	return (PRIV_POLICY(cr, PRIV_NET_MAC_AWARE, B_FALSE, EACCES,
+	    NULL));
+}
+
+/*
  * Common routine which determines whether a given credential can
  * act on a given mount.
  * When called through mount, the parameter needoptcheck is a pointer
@@ -1677,6 +1693,12 @@
 	return (secpolicy_require_set(cr, PRIV_FULLSET, NULL));
 }
 
+boolean_t
+secpolicy_net_reply_equal(const cred_t *cr)
+{
+	return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL));
+}
+
 int
 secpolicy_swapctl(const cred_t *cr)
 {
--- a/usr/src/uts/common/os/priv_defs	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/priv_defs	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
 INSERT COMMENT
@@ -105,6 +104,14 @@
 	In order to write files owned by uid 0 in the absence of an
 	effective uid of 0 ALL privileges are required.
 
+privilege PRIV_FILE_DOWNGRADE_SL
+
+	Allows a process to set the sensitivity label of a file or
+	directory to a sensitivity label that does not dominate the
+	existing sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 basic privilege PRIV_FILE_LINK_ANY
 
 	Allows a process to create hardlinks to files owned by a uid
@@ -134,6 +141,14 @@
 	Additional restrictions apply when creating or modifying a
 	set-uid 0 file.
 
+privilege PRIV_FILE_UPGRADE_SL
+
+	Allows a process to set the sensitivity label of a file or
+	directory to a sensitivity label that dominates the existing
+	sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 privilege PRIV_GART_ACCESS
 
 	Allows a process to make ioctls to agpgart device except
@@ -175,10 +190,33 @@
 	Additional restrictions apply if the owner of the object has uid 0
 	and the effective uid of the current process is not 0.
 
+privilege PRIV_NET_BINDMLP
+
+	Allow a process to bind to a port that is configured as a
+	multi-level port(MLP) for the process's zone. This privilege
+	applies to both shared address and zone-specific address MLPs.
+	See tnzonecfg(4) from the Trusted Extensions manual pages for
+	information on configuring MLP ports.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 privilege PRIV_NET_ICMPACCESS
 
 	Allows a process to send and receive ICMP packets.
 
+privilege PRIV_NET_MAC_AWARE
+
+	Allows a process to set NET_MAC_AWARE process flag by using 
+	setpflags(2). This privilege also allows a process to set
+	SO_MAC_EXEMPT socket option by using setsockopt(3SOCKET).
+	The NET_MAC_AWARE process flag and the SO_MAC_EXEMPT socket
+	option both allow a local process to communicate with an
+	unlabeled peer if the local process' label dominates the
+	peer's default label, or if the local process runs in the
+	global zone.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 privilege PRIV_NET_PRIVADDR
 
 	Allows a process to bind to a privileged port
@@ -374,6 +412,117 @@
 	Allows a process to manipulate system time using any of the
 	appropriate system calls: stime, adjtime, ntp_adjtime and
 	the IA specific RTC calls.
+
+privilege PRIV_SYS_TRANS_LABEL
+
+	Allows a process to translate labels that are not dominated
+	by the process' sensitivity label to and from an external
+	string form.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_COLORMAP
+
+	Allows a process to override colormap restrictions.
+        Allows a process to install or remove colormaps.
+        Allows a process to retrieve colormap cell entries allocated
+	by other processes.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_CONFIG
+
+	Allows a process to configure or destroy resources that are
+	permanently retained by the X server.
+        Allows a process to use SetScreenSaver to set the screen
+	saver timeout value.
+        Allows a process to use ChangeHosts to modify the display
+	access control list.
+        Allows a process to use GrabServer.
+        Allows a process to use the SetCloseDownMode request which
+	may retain window, pixmap, colormap, property, cursor, font,
+	or graphic context resources.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_DAC_READ
+
+	Allows a process to read from a window resource that it does
+	not own (has a different user ID).
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_DAC_WRITE
+
+	Allows a process to write to or create a window resource that
+	it does not own (has a different user ID). A newly created
+	window property is created with the window's user ID.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_DEVICES
+
+	Allows a process to perform operations on window input devices.
+        Allows a process to get and set keyboard and pointer controls.
+        Allows a process to modify pointer button and key mappings.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_DGA
+
+	Allows a process to use the direct graphics access (DGA) X protocol
+	extensions. Direct process access to the frame buffer is still
+	required. Thus the process must have MAC and DAC privileges that
+	allow access to the frame buffer, or the frame buffer must be
+        allocated to the process.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_DOWNGRADE_SL
+
+	Allows a process to set the sensitivity label of a window resource
+	to a sensitivity label that does not dominate the existing
+	sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_FONTPATH
+
+	Allows a process to set a font path.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_MAC_READ
+
+	Allows a process to read from a window resource whose sensitivity
+	label is not equal to the process sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_MAC_WRITE
+
+	Allows a process to create a window resource whose sensitivity
+	label is not equal to the process sensitivity label.
+	A newly created window property is created with the window's
+	sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_SELECTION
+
+	Allows a process to request inter-window data moves without the
+	intervention of the selection confirmer.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
+privilege PRIV_WIN_UPGRADE_SL
+
+	Allows a process to set the sensitivity label of a window
+	resource to a sensitivity label that dominates the existing
+	sensitivity label.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 set PRIV_EFFECTIVE
 
 	Set of privileges currently in effect.
--- a/usr/src/uts/common/os/sysent.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/sysent.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 /* ONC_PLUS EXTRACT START */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -83,6 +82,7 @@
 int	ioctl();
 int	issetugid();
 int	kill();
+int	labelsys();
 int	link();
 off32_t	lseek32();
 off_t	lseek64();
@@ -664,7 +664,7 @@
 	/* 181 */ SYSENT_CI("rusagesys",	rusagesys, 	2),
 	/* 182 */ SYSENT_LOADABLE(),		/* portfs */
 	/* 183 */ SYSENT_CI("pollsys",		pollsys,	4),
-	/* 184 */ SYSENT_LOADABLE(),		/* tsolsys */
+	/* 184 */ SYSENT_CI("labelsys",		labelsys,	5),
 	/* 185 */ SYSENT_CI("acl",		acl,		4),
 	/* 186 */ SYSENT_AP("auditsys",		auditsys,	2),
 	/* 187 */ SYSENT_CI("processor_bind",	processor_bind,	4),
@@ -742,7 +742,7 @@
 			SYSENT_NOSYS(),
 			SYSENT_CI("open64",	open64,		3)),
 	/* 226 */ SYSENT_LOADABLE(),		/* rpcsys */
-	/* 227 */ SYSENT_CL("zone",		zone,		6),
+	/* 227 */ SYSENT_CL("zone",		zone,		5),
 	/* 228 */ SYSENT_LOADABLE(),		/* autofssys */
 	/* 229 */ SYSENT_CI("getcwd",		getcwd,		2),
 	/* 230 */ SYSENT_CI("so_socket",	so_socket,	5),
@@ -1042,7 +1042,7 @@
 	/* 181 */ SYSENT_CI("rusagesys",	rusagesys,	2),
 	/* 182 */ SYSENT_LOADABLE32(),		/* portfs */
 	/* 183 */ SYSENT_CI("pollsys",		pollsys,	4),
-	/* 184 */ SYSENT_LOADABLE32(),		/* tsolsys */
+	/* 184 */ SYSENT_CI("labelsys",		labelsys,	5),
 	/* 185 */ SYSENT_CI("acl",		acl,		4),
 	/* 186 */ SYSENT_AP("auditsys",		auditsys,	2),
 	/* 187 */ SYSENT_CI("processor_bind",	processor_bind,	4),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/os/tlabel.c	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,621 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/cred.h>
+#include <sys/modctl.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/tiuser.h>
+#include <sys/kmem.h>
+#include <sys/pathname.h>
+#include <sys/zone.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+#include <sys/fs/lofs_node.h>
+#include <inet/ip6.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include <nfs/nfs.h>
+#include <nfs/nfs4.h>
+#include <nfs/nfs_clnt.h>
+#include <sys/dnlc.h>
+
+
+int sys_labeling = -1;			/* initially unset */
+
+static kmem_cache_t *tslabel_cache;
+ts_label_t *l_admin_low;
+ts_label_t *l_admin_high;
+
+uint32_t default_doi = DEFAULT_DOI;
+
+/*
+ * Initialize labels infrastructure.
+ * This is called during startup() time (before vfs_mntroot) by thread_init().
+ * It has to be called early so that the is_system_labeled() function returns
+ * the right value when called by the networking code on a diskless boot.
+ */
+void
+label_init(void)
+{
+	bslabel_t label;
+
+	/*
+	 * Use the value of "label_services" within the edition module.
+	 * If for some reason label_services is not found, this will
+	 * result in the appropriate default -- "off."
+	 */
+	if (modgetsymvalue("label_services", B_FALSE) != 0)
+		sys_labeling = 1;
+	else
+		sys_labeling = 0;
+
+	tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t),
+	    0, NULL, NULL, NULL, NULL, NULL, 0);
+	bsllow(&label);
+	l_admin_low = labelalloc(&label, default_doi, KM_SLEEP);
+	bslhigh(&label);
+	l_admin_high = labelalloc(&label, default_doi, KM_SLEEP);
+}
+
+/*
+ * Allocate new ts_label_t.
+ */
+ts_label_t *
+labelalloc(const bslabel_t *val, uint32_t doi, int flag)
+{
+	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
+
+	if (lab != NULL) {
+		lab->tsl_ref = 1;
+		lab->tsl_doi = doi;
+		if (val == NULL)
+			bzero(&lab->tsl_label, sizeof (bslabel_t));
+		else
+			bcopy(val, &lab->tsl_label,  sizeof (bslabel_t));
+	}
+	return (lab);
+}
+
+/*
+ * Put a hold on a label structure.
+ */
+void
+label_hold(ts_label_t *lab)
+{
+	atomic_add_32(&lab->tsl_ref, 1);
+}
+
+/*
+ * Release previous hold on a label structure.  Free it if refcnt == 0.
+ */
+void
+label_rele(ts_label_t *lab)
+{
+	if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0)
+		kmem_cache_free(tslabel_cache, lab);
+}
+
+bslabel_t *
+label2bslabel(ts_label_t *lab)
+{
+	return (&lab->tsl_label);
+}
+
+
+uint32_t
+label2doi(ts_label_t *lab)
+{
+	return (lab->tsl_doi);
+}
+
+/*
+ * Compare labels. Return 1 if equal, 0 otherwise.
+ */
+boolean_t
+label_equal(const ts_label_t *l1, const ts_label_t *l2)
+{
+	return ((l1->tsl_doi == l2->tsl_doi) &&
+	    blequal(&l1->tsl_label, &l2->tsl_label));
+}
+
+/*
+ * There's no protocol today to obtain the label from the server.
+ * So we rely on conventions: zones, zone names, and zone paths
+ * must match across TX servers and their TX clients.  Now use
+ * the exported name to find the equivalent local zone and its
+ * label.  Caller is responsible for doing a label_rele of the
+ * returned ts_label.
+ */
+ts_label_t *
+getflabel_cipso(vfs_t *vfsp)
+{
+	zone_t	*reszone;
+	zone_t	*new_reszone;
+	char	*nfspath, *respath;
+	refstr_t	*resource_ref;
+	boolean_t	treat_abs = B_FALSE;
+
+	if (vfsp->vfs_resource == NULL)
+		return (NULL);			/* error */
+	resource_ref = vfs_getresource(vfsp);
+
+	nfspath = (char *)refstr_value(resource_ref);
+	respath = strchr(nfspath, ':');		/* skip server name */
+	if (respath)
+		respath++;			/* skip over ":" */
+	if (*respath != '/') {
+		/* treat path as absolute but it doesn't have leading '/' */
+		treat_abs = B_TRUE;
+	}
+
+	reszone = zone_find_by_any_path(respath, treat_abs);
+	if (reszone == global_zone) {
+		refstr_rele(resource_ref);
+		label_hold(l_admin_low);
+		zone_rele(reszone);
+		return (l_admin_low);
+	}
+
+	/*
+	 * Skip over zonepath (not including "root"), e.g. /zone/internal
+	 */
+	respath += reszone->zone_rootpathlen - 7;
+	if (treat_abs)
+		respath--;			/* no leading '/' to skip */
+	if (strncmp(respath, "/root/", 6) == 0) {
+		/* Check if we now have something like "/zone/public/" */
+
+		respath += 5;			/* skip "/root" first */
+		new_reszone = zone_find_by_any_path(respath, B_FALSE);
+		if (new_reszone != global_zone) {
+			zone_rele(reszone);
+			reszone = new_reszone;
+		} else {
+			zone_rele(new_reszone);
+		}
+	}
+
+	refstr_rele(resource_ref);
+	label_hold(reszone->zone_slabel);
+	zone_rele(reszone);
+
+	return (reszone->zone_slabel);
+}
+
+static ts_label_t *
+getflabel_nfs(vfs_t *vfsp)
+{
+	bslabel_t	*server_sl;
+	ts_label_t	*srv_label;
+	tsol_tpc_t	*tp;
+	int		addr_type;
+	void		*ipaddr;
+	struct servinfo *svp;
+	struct netbuf	*addr;
+	struct knetconfig *knconf;
+	mntinfo_t	*mi;
+
+	mi = VFTOMI(vfsp);
+	svp = mi->mi_curr_serv;
+	addr = &svp->sv_addr;
+	knconf = svp->sv_knconf;
+
+	if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
+		addr_type = IPV4_VERSION;
+		/* LINTED: following cast to ipaddr is OK */
+		ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
+	} else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
+		addr_type = IPV6_VERSION;
+		/* LINTED: following cast to ipaddr is OK */
+		ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
+	} else {
+		goto errout;
+	}
+
+	tp = find_tpc(ipaddr, addr_type, B_FALSE);
+	if (tp == NULL)
+		goto errout;
+
+	if (tp->tpc_tp.host_type == SUN_CIPSO) {
+		TPC_RELE(tp);
+		return (getflabel_cipso(vfsp));
+	}
+
+	if (tp->tpc_tp.host_type != UNLABELED)
+		goto errout;
+
+	server_sl = &tp->tpc_tp.tp_def_label;
+	srv_label = labelalloc(server_sl, default_doi, KM_SLEEP);
+
+	TPC_RELE(tp);
+
+	return (srv_label);
+
+errout:
+	return (NULL);
+}
+
+/*
+ * getflabel -
+ *
+ * Return pointer to the ts_label associated with the specified file,
+ * or returns NULL if error occurs.  Caller is responsible for doing
+ * a label_rele of the ts_label.
+ */
+ts_label_t *
+getflabel(vnode_t *vp)
+{
+	vfs_t		*vfsp, *rvfsp, *nvfs;
+	vnode_t		*rvp, *rvp2;
+	zone_t		*zone;
+	ts_label_t	*zl;
+	boolean_t	vfs_is_held = B_FALSE;
+	refstr_t	*resource_ref = NULL;
+	char		*resource = NULL;
+	char		vpath[MAXPATHLEN];
+
+	ASSERT(vp);
+	vfsp = rvfsp = nvfs = vp->v_vfsp;
+	if (vfsp == NULL)
+		return (NULL);
+
+	rvp = rvp2 = vp;
+
+	/*
+	 * Get rid of all but the last loopback vfs, since the last such mount
+	 * has the correct resource to use (except for nfs case, handled later).
+	 */
+	while (strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "lofs") == 0) {
+		rvp = rvp2;
+		rvfsp = nvfs;
+		if ((rvp2 = realvp(rvp)) == NULL)
+			break;
+		if (((nvfs = rvp2->v_vfsp) == NULL) || (nvfs == rvfsp))
+			break;
+	}
+
+	/*
+	 * rvp/rvfsp now represent the preliminary vnode/vfs we may use.  Now
+	 * check if the next vfs is nfs; if so, then it has the correct info
+	 * to use.  And finally, for some cases on loop-back mounts there will
+	 * be no resource; for these, use the underlying vfs also.
+	 */
+	if (strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, "lofs") == 0) {
+		if (((rvp2 = realvp(rvp)) != NULL) &&
+		    ((nvfs = rvp2->v_vfsp) != NULL) &&
+		    ((strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "nfs") == 0)) ||
+		    (rvfsp->vfs_resource == NULL)) {
+			rvp = rvp2;
+			rvfsp = nvfs;
+		}
+	}
+
+	/* rvp/rvfsp now represent the real vnode/vfs we will be using */
+
+	/* Go elsewhere to handle all nfs files. */
+	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
+		return (getflabel_nfs(rvfsp));
+
+	/*
+	 * Fast path, for objects in a labeled zone: everything except
+	 * for lofs/nfs will be just the label of that zone.
+	 */
+	if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
+		if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
+		    "lofs") != 0)) {
+			zone = rvfsp->vfs_zone;
+			zone_hold(zone);
+			goto zone_out;		/* return this label */
+		}
+	}
+
+	if (rvfsp->vfs_resource) {
+		resource_ref = vfs_getresource(rvfsp);
+		resource = (char *)refstr_value(resource_ref);
+	}
+
+	/*
+	 * Sanity check - resource may be weird for some cases, like devices.
+	 * In this case, the label must be "local", so just use the mount point.
+	 */
+	if ((resource == NULL) || (*resource != '/')) {
+		if (resource_ref)
+			refstr_rele(resource_ref);
+		if (rvfsp->vfs_mntpt) {
+			resource_ref = vfs_getmntpoint(rvfsp);
+			resource = (char *)refstr_value(resource_ref);
+		}
+		if ((resource == NULL) || (*resource != '/')) {
+			zone = curproc->p_zone;
+			zone_hold(zone);
+			goto zone_out;
+		}
+	}
+
+	VFS_HOLD(vfsp);
+	vfs_is_held = B_TRUE;
+
+	zone = zone_find_by_any_path(resource, B_FALSE);
+
+	/*
+	 * If the vfs source zone is properly set to a non-global zone, or
+	 * any zone if the mount is R/W, then use the label of that zone.
+	 */
+	if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
+		goto zone_out;		/* return this label */
+
+	/*
+	 * Otherwise, if we're not in the global zone, use the label of
+	 * our zone.
+	 */
+	if ((zone = curproc->p_zone) != global_zone) {
+		zone_hold(zone);
+		goto zone_out;		/* return this label */
+	}
+
+	/*
+	 * We're in the global zone and the mount is R/W ... so the file
+	 * may actually be in the global zone -- or in the root of any zone.
+	 * Always build our own path for the file, to be sure it's simplified
+	 * (i.e., no ".", "..", "//", and so on).
+	 */
+	if (vnodetopath(NULL, vp, vpath, sizeof (vpath), CRED()) != 0) {
+		if (vfs_is_held)
+			VFS_RELE(vfsp);
+		if (resource_ref)
+			refstr_rele(resource_ref);
+		zone_rele(zone);
+		return (NULL);
+	}
+
+	zone_rele(zone);
+	zone = zone_find_by_any_path(vpath, B_FALSE);
+
+zone_out:
+	if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
+		vfs_t		*nvfs;
+		boolean_t	exported = B_FALSE;
+		refstr_t	*mntpt_ref;
+		char		*mntpt;
+
+		/*
+		 * File is in the global zone - check whether it's admin_high.
+		 * If it's in a filesys that was exported from the global zone,
+		 * it's admin_low by definition.  Otherwise, if it's in a
+		 * filesys that's NOT exported to any zone, it's admin_high.
+		 *
+		 * And for these files if there wasn't a valid mount resource,
+		 * the file must be admin_high (not exported, probably a global
+		 * zone device).
+		 */
+		if (!vfs_is_held)
+			goto out_high;
+
+		mntpt_ref = vfs_getmntpoint(vfsp);
+		mntpt = (char *)refstr_value(mntpt_ref);
+
+		if ((mntpt != NULL) && (*mntpt == '/')) {
+			zone_t	*to_zone;
+
+			to_zone = zone_find_by_any_path(mntpt, B_FALSE);
+			zone_rele(to_zone);
+			if (to_zone != global_zone) {
+				/* force admin_low */
+				exported = B_TRUE;
+			}
+		}
+		if (mntpt_ref)
+			refstr_rele(mntpt_ref);
+
+		if (!exported) {
+			size_t	plen = strlen(vpath);
+
+			vfs_list_read_lock();
+			nvfs = vfsp->vfs_next;
+			while (nvfs != vfsp) {
+				const char	*rstr;
+				size_t		rlen = 0;
+
+				rstr = refstr_value(nvfs->vfs_resource);
+				if (rstr != NULL)
+					rlen = strlen(rstr);
+
+				/*
+				 * Check for a match: does this vfs correspond
+				 * to our global zone file path?  I.e., check
+				 * if the resource string of this vfs is a
+				 * prefix of our path.
+				 */
+				if ((rlen > 0) && (rlen <= plen) &&
+				    (strncmp(rstr, vpath, rlen) == 0) &&
+				    (vpath[rlen] == '/' ||
+				    vpath[rlen] == '\0')) {
+					/* force admin_low */
+					exported = B_TRUE;
+					break;
+				}
+				nvfs = nvfs->vfs_next;
+			}
+			vfs_list_unlock();
+		}
+
+		if (!exported)
+			goto out_high;
+	}
+
+	if (vfs_is_held)
+		VFS_RELE(vfsp);
+
+	if (resource_ref)
+		refstr_rele(resource_ref);
+
+	/*
+	 * Now that we have the "home" zone for the file, return the slabel
+	 * of that zone.
+	 */
+	zl = zone->zone_slabel;
+	label_hold(zl);
+	zone_rele(zone);
+	return (zl);
+
+out_high:
+	if (vfs_is_held)
+		VFS_RELE(vfsp);
+	if (resource_ref)
+		refstr_rele(resource_ref);
+
+	label_hold(l_admin_high);
+	zone_rele(zone);
+	return (l_admin_high);
+}
+
+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);
+}
+
+/*
+ * fgetlabel(2TSOL) - get file label
+ * getlabel(2TSOL) - get file label
+ */
+int
+getlabel(const char *path, bslabel_t *label_p)
+{
+	struct		vnode	*vp;
+	char		*spath;
+	int		error;
+
+	/* Sanity check arguments */
+	if (path == NULL)
+		return (set_errno(EINVAL));
+
+	spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+	if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) {
+		kmem_free(spath, MAXPATHLEN);
+		return (set_errno(error));
+	}
+
+	if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) {
+		kmem_free(spath, MAXPATHLEN);
+		return (set_errno(error));
+	}
+	kmem_free(spath, MAXPATHLEN);
+
+	error = cgetlabel(label_p, vp);
+
+	VN_RELE(vp);
+	if (error != 0)
+		return (set_errno(error));
+	else
+		return (0);
+}
+
+int
+fgetlabel(int fd, bslabel_t *label_p)
+{
+	file_t		*fp;
+	int		error;
+
+	if ((fp = getf(fd)) == NULL)
+		return (set_errno(EBADF));
+
+	error = cgetlabel(label_p, fp->f_vnode);
+	releasef(fd);
+
+	if (error != 0)
+		return (set_errno(error));
+	else
+		return (0);
+}
+
+/*
+ * Used by NFSv4 to query label of a pathname
+ * component during lookup/access ops.
+ */
+ts_label_t *
+nfs4_getflabel(vnode_t *vp)
+{
+	zone_t *zone;
+	ts_label_t *zone_label;
+	char path[MAXNAMELEN];
+	vnode_t *pvp, *tvp;
+
+	mutex_enter(&vp->v_lock);
+	/*
+	 * mount traverse has been done by caller
+	 * before calling this routine.
+	 */
+	ASSERT(!vn_ismntpt(vp));
+	if (vp->v_path != NULL) {
+		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
+		mutex_exit(&vp->v_lock);
+	} else {
+		/*
+		 * v_path not cached. Since we rely on path
+		 * of an obj to get its label, we need to get
+		 * path corresponding to the parent vnode.
+		 */
+		tvp = vp;
+		do {
+			mutex_exit(&tvp->v_lock);
+			if ((pvp = dnlc_reverse_lookup(tvp, path,
+			    sizeof (path))) == NULL)
+				return (NULL);
+			mutex_enter(&pvp->v_lock);
+			tvp = pvp;
+		} while (pvp->v_path == NULL);
+		zone = zone_find_by_any_path(pvp->v_path, B_FALSE);
+		mutex_exit(&pvp->v_lock);
+	}
+	/*
+	 * Caller has verified that the file is either
+	 * exported or visible. So if the path falls in
+	 * global zone, admin_low is returned; otherwise
+	 * the zone's label is returned.
+	 */
+	zone_label = zone->zone_slabel;
+	label_hold(zone_label);
+	zone_rele(zone);
+	return (zone_label);
+}
--- a/usr/src/uts/common/os/zone.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/os/zone.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -186,11 +185,11 @@
 #include <sys/priv_impl.h>
 #include <sys/cred.h>
 #include <c2/audit.h>
-#include <sys/ddi.h>
 #include <sys/debug.h>
 #include <sys/file.h>
 #include <sys/kmem.h>
 #include <sys/mutex.h>
+#include <sys/note.h>
 #include <sys/pathname.h>
 #include <sys/proc.h>
 #include <sys/project.h>
@@ -210,7 +209,6 @@
 #include <sys/pool.h>
 #include <sys/pool_pset.h>
 #include <sys/pset.h>
-#include <sys/log.h>
 #include <sys/sysmacros.h>
 #include <sys/callb.h>
 #include <sys/vmparam.h>
@@ -218,7 +216,6 @@
 
 #include <sys/door.h>
 #include <sys/cpuvar.h>
-#include <sys/fs/snode.h>
 
 #include <sys/uadmin.h>
 #include <sys/session.h>
@@ -228,6 +225,7 @@
 #include <sys/rctl.h>
 #include <sys/fss.h>
 #include <sys/zone.h>
+#include <sys/tsol/label.h>
 
 /*
  * cv used to signal that all references to the zone have been released.  This
@@ -255,7 +253,7 @@
 static list_t zsd_registered_keys;
 
 int zone_hash_size = 256;
-static mod_hash_t *zonehashbyname, *zonehashbyid;
+static mod_hash_t *zonehashbyname, *zonehashbyid, *zonehashbylabel;
 static kmutex_t zonehash_lock;
 static uint_t zonecount;
 static id_space_t *zoneid_space;
@@ -323,6 +321,7 @@
 static kmutex_t mount_lock;
 
 const char * const zone_initname = "/sbin/init";
+static char * const zone_prefix = "/zone/";
 
 static int zone_shutdown(zoneid_t zoneid);
 
@@ -337,8 +336,10 @@
  *     error reporting when zone_create() fails.
  * Version 3 alters the zone_create system call in order to support the
  *     import of ZFS datasets to zones.
+ * Version 4 alters the zone_create system call in order to support
+ *     Trusted Extensions.
  */
-static const int ZONE_SYSCALL_API_VERSION = 3;
+static const int ZONE_SYSCALL_API_VERSION = 4;
 
 /*
  * Certain filesystems (such as NFS and autofs) need to know which zone
@@ -998,6 +999,51 @@
 }
 
 /*
+ * Compute a hash value based on the contents of the label and the DOI.  The
+ * hash algorithm is somewhat arbitrary, but is based on the observation that
+ * humans will likely pick labels that differ by amounts that work out to be
+ * multiples of the number of hash chains, and thus stirring in some primes
+ * should help.
+ */
+static uint_t
+hash_bylabel(void *hdata, mod_hash_key_t key)
+{
+	const ts_label_t *lab = (ts_label_t *)key;
+	const uint32_t *up, *ue;
+	uint_t hash;
+	int i;
+
+	_NOTE(ARGUNUSED(hdata));
+
+	hash = lab->tsl_doi + (lab->tsl_doi << 1);
+	/* we depend on alignment of label, but not representation */
+	up = (const uint32_t *)&lab->tsl_label;
+	ue = up + sizeof (lab->tsl_label) / sizeof (*up);
+	i = 1;
+	while (up < ue) {
+		/* using 2^n + 1, 1 <= n <= 16 as source of many primes */
+		hash += *up + (*up << ((i % 16) + 1));
+		up++;
+		i++;
+	}
+	return (hash);
+}
+
+/*
+ * All that mod_hash cares about here is zero (equal) versus non-zero (not
+ * equal).  This may need to be changed if less than / greater than is ever
+ * needed.
+ */
+static int
+hash_labelkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+	ts_label_t *lab1 = (ts_label_t *)key1;
+	ts_label_t *lab2 = (ts_label_t *)key2;
+
+	return (label_equal(lab1, lab2) ? 0 : 1);
+}
+
+/*
  * Called by main() to initialize the zones framework.
  */
 void
@@ -1063,20 +1109,42 @@
 	 * pool_default hasn't been initialized yet, so we let pool_init() take
 	 * care of making the global zone is in the default pool.
 	 */
+
+	/*
+	 * Initialize zone label.
+	 * mlp are initialized when tnzonecfg is loaded.
+	 */
+	zone0.zone_slabel = l_admin_low;
+	rw_init(&zone0.zone_mlps.mlpl_rwlock, NULL, RW_DEFAULT, NULL);
+	label_hold(l_admin_low);
+
 	mutex_enter(&zonehash_lock);
 	zone_uniqid(&zone0);
 	ASSERT(zone0.zone_uniqid == GLOBAL_ZONEUNIQID);
-	mutex_exit(&zonehash_lock);
+
 	zonehashbyid = mod_hash_create_idhash("zone_by_id", zone_hash_size,
 	    mod_hash_null_valdtor);
 	zonehashbyname = mod_hash_create_strhash("zone_by_name",
 	    zone_hash_size, mod_hash_null_valdtor);
+	/*
+	 * maintain zonehashbylabel only for labeled systems
+	 */
+	if (is_system_labeled())
+		zonehashbylabel = mod_hash_create_extended("zone_by_label",
+		    zone_hash_size, mod_hash_null_keydtor,
+		    mod_hash_null_valdtor, hash_bylabel, NULL,
+		    hash_labelkey_cmp, KM_SLEEP);
 	zonecount = 1;
 
 	(void) mod_hash_insert(zonehashbyid, (mod_hash_key_t)GLOBAL_ZONEID,
 	    (mod_hash_val_t)&zone0);
 	(void) mod_hash_insert(zonehashbyname, (mod_hash_key_t)zone0.zone_name,
 	    (mod_hash_val_t)&zone0);
+	if (is_system_labeled())
+		(void) mod_hash_insert(zonehashbylabel,
+		    (mod_hash_key_t)zone0.zone_slabel, (mod_hash_val_t)&zone0);
+	mutex_exit(&zonehash_lock);
+
 	/*
 	 * We avoid setting zone_kcred until now, since kcred is initialized
 	 * sometime after zone_zsd_init() and before zone_init().
@@ -1126,6 +1194,8 @@
 		kmem_free(zone->zone_rootpath, zone->zone_rootpathlen);
 	if (zone->zone_name != NULL)
 		kmem_free(zone->zone_name, ZONENAME_MAX);
+	if (zone->zone_slabel != NULL)
+		label_rele(zone->zone_slabel);
 	if (zone->zone_nodename != NULL)
 		kmem_free(zone->zone_nodename, _SYS_NMLN);
 	if (zone->zone_domain != NULL)
@@ -1139,6 +1209,7 @@
 	id_free(zoneid_space, zone->zone_id);
 	mutex_destroy(&zone->zone_lock);
 	cv_destroy(&zone->zone_cv);
+	rw_destroy(&zone->zone_mlps.mlpl_rwlock);
 	kmem_free(zone, sizeof (zone_t));
 }
 
@@ -1513,6 +1584,24 @@
 }
 
 static zone_t *
+zone_find_all_by_label(const ts_label_t *label)
+{
+	mod_hash_val_t hv;
+	zone_t *zone = NULL;
+
+	ASSERT(MUTEX_HELD(&zonehash_lock));
+
+	/*
+	 * zonehashbylabel is not maintained for unlabeled systems
+	 */
+	if (!is_system_labeled())
+		return (NULL);
+	if (mod_hash_find(zonehashbylabel, (mod_hash_key_t)label, &hv) == 0)
+		zone = (zone_t *)hv;
+	return (zone);
+}
+
+static zone_t *
 zone_find_all_by_name(char *name)
 {
 	mod_hash_val_t hv;
@@ -1558,6 +1647,34 @@
 }
 
 /*
+ * Similar to zone_find_by_id, but using zone label as the key.
+ */
+zone_t *
+zone_find_by_label(const ts_label_t *label)
+{
+	zone_t *zone;
+
+	mutex_enter(&zonehash_lock);
+	if ((zone = zone_find_all_by_label(label)) == NULL) {
+		mutex_exit(&zonehash_lock);
+		return (NULL);
+	}
+	mutex_enter(&zone_status_lock);
+	if (zone_status_get(zone) > ZONE_IS_DOWN) {
+		/*
+		 * For all practical purposes the zone doesn't exist.
+		 */
+		mutex_exit(&zone_status_lock);
+		zone = NULL;
+	} else {
+		mutex_exit(&zone_status_lock);
+		zone_hold(zone);
+	}
+	mutex_exit(&zonehash_lock);
+	return (zone);
+}
+
+/*
  * Similar to zone_find_by_id, but using zone name as the key.
  */
 zone_t *
@@ -2591,6 +2708,23 @@
 	return (set_errno(er_error));
 }
 
+static int
+zone_set_label(zone_t *zone, const bslabel_t *lab, uint32_t doi)
+{
+	ts_label_t *tsl;
+	bslabel_t blab;
+
+	/* Get label from user */
+	if (copyin(lab, &blab, sizeof (blab)) != 0)
+		return (EFAULT);
+	tsl = labelalloc(&blab, doi, KM_NOSLEEP);
+	if (tsl == NULL)
+		return (ENOMEM);
+
+	zone->zone_slabel = tsl;
+	return (0);
+}
+
 /*
  * Parses a comma-separated list of ZFS datasets into a per-zone dictionary.
  */
@@ -2643,7 +2777,8 @@
 /*
  * System call to create/initialize a new zone named 'zone_name', rooted
  * at 'zone_root', with a zone-wide privilege limit set of 'zone_privs',
- * and initialized with the zone-wide rctls described in 'rctlbuf'.
+ * and initialized with the zone-wide rctls described in 'rctlbuf', and
+ * with labeling set by 'match', 'doi', and 'label'.
  *
  * If extended error is non-null, we may use it to return more detailed
  * error information.
@@ -2652,7 +2787,8 @@
 zone_create(const char *zone_name, const char *zone_root,
     const priv_set_t *zone_privs, size_t zone_privssz,
     caddr_t rctlbuf, size_t rctlbufsz,
-    caddr_t zfsbuf, size_t zfsbufsz, int *extended_error)
+    caddr_t zfsbuf, size_t zfsbufsz, int *extended_error,
+    int match, uint32_t doi, const bslabel_t *label)
 {
 	struct zsched_arg zarg;
 	nvlist_t *rctls = NULL;
@@ -2687,6 +2823,7 @@
 	    offsetof(struct zsd_entry, zsd_linkage));
 	list_create(&zone->zone_datasets, sizeof (zone_dataset_t),
 	    offsetof(zone_dataset_t, zd_linkage));
+	rw_init(&zone->zone_mlps.mlpl_rwlock, NULL, RW_DEFAULT, NULL);
 
 	if ((error = zone_set_name(zone, zone_name)) != 0) {
 		zone_free(zone);
@@ -2728,6 +2865,23 @@
 	}
 
 	/*
+	 * Read in the trusted system parameters:
+	 * match flag and sensitivity label.
+	 */
+	zone->zone_match = match;
+	if (is_system_labeled()) {
+		error = zone_set_label(zone, label, doi);
+		if (error != 0) {
+			zone_free(zone);
+			return (set_errno(error));
+		}
+	} else {
+		/* all zones get an admin_low label if system is not labeled */
+		zone->zone_slabel = l_admin_low;
+		label_hold(l_admin_low);
+	}
+
+	/*
 	 * Stop all lwps since that's what normally happens as part of fork().
 	 * This needs to happen before we grab any locks to avoid deadlock
 	 * (another lwp in the process could be waiting for the held lock).
@@ -2765,8 +2919,13 @@
 	mutex_enter(&zonehash_lock);
 	/*
 	 * Make sure zone doesn't already exist.
+	 *
+	 * If the system and zone are labeled,
+	 * make sure no other zone exists that has the same label.
 	 */
-	if ((ztmp = zone_find_all_by_name(zone->zone_name)) != NULL) {
+	if ((ztmp = zone_find_all_by_name(zone->zone_name)) != NULL ||
+	    (zone->zone_slabel != NULL &&
+	    (ztmp = zone_find_all_by_label(zone->zone_slabel)) != NULL)) {
 		zone_status_t status;
 
 		status = zone_status_get(ztmp);
@@ -2813,6 +2972,11 @@
 	(void) strcpy(str, zone->zone_name);
 	(void) mod_hash_insert(zonehashbyname, (mod_hash_key_t)str,
 	    (mod_hash_val_t)(uintptr_t)zone);
+	if (is_system_labeled()) {
+		(void) mod_hash_insert(zonehashbylabel,
+		    (mod_hash_key_t)zone->zone_slabel, (mod_hash_val_t)zone);
+	}
+
 	/*
 	 * Insert into active list.  At this point there are no 'hold's
 	 * on the zone, but everyone else knows not to use it, so we can
@@ -2836,6 +3000,11 @@
 		 */
 		mutex_enter(&zonehash_lock);
 		list_remove(&zone_active, zone);
+		if (is_system_labeled()) {
+			ASSERT(zone->zone_slabel != NULL);
+			(void) mod_hash_destroy(zonehashbylabel,
+			    (mod_hash_key_t)zone->zone_slabel);
+		}
 		(void) mod_hash_destroy(zonehashbyname,
 		    (mod_hash_key_t)(uintptr_t)zone->zone_name);
 		(void) mod_hash_destroy(zonehashbyid,
@@ -2982,6 +3151,42 @@
 }
 
 /*
+ * This function implements the policy for zone visibility.
+ *
+ * In standard Solaris, a non-global zone can only see itself.
+ *
+ * In Trusted Extensions, a labeled zone can lookup any zone whose label
+ * it dominates. For this test, the label of the global zone is treated as
+ * admin_high so it is special-cased instead of being checked for dominance.
+ *
+ * Returns true if zone attributes are viewable, false otherwise.
+ */
+static boolean_t
+zone_list_access(zone_t *zone)
+{
+
+	if (curproc->p_zone == global_zone ||
+	    curproc->p_zone == zone) {
+		return (B_TRUE);
+	} else if (is_system_labeled()) {
+		bslabel_t *curproc_label;
+		bslabel_t *zone_label;
+
+		curproc_label = label2bslabel(curproc->p_zone->zone_slabel);
+		zone_label = label2bslabel(zone->zone_slabel);
+
+		if (zone->zone_id != GLOBAL_ZONEID &&
+		    bldominates(curproc_label, zone_label)) {
+			return (B_TRUE);
+		} else {
+			return (B_FALSE);
+		}
+	} else {
+		return (B_FALSE);
+	}
+}
+
+/*
  * Systemcall to start the zone's halt sequence.  By the time this
  * function successfully returns, all user processes and kernel threads
  * executing in it will have exited, ZSD shutdown callbacks executed,
@@ -3237,6 +3442,9 @@
 	    (mod_hash_key_t)zone->zone_name);
 	(void) mod_hash_destroy(zonehashbyid,
 	    (mod_hash_key_t)(uintptr_t)zone->zone_id);
+	if (is_system_labeled() && zone->zone_slabel != NULL)
+		(void) mod_hash_destroy(zonehashbylabel,
+		    (mod_hash_key_t)zone->zone_slabel);
 	mutex_exit(&zonehash_lock);
 
 	/*
@@ -3274,6 +3482,7 @@
 	zone_status_t zone_status;
 	pid_t initpid;
 	boolean_t global = (curproc->p_zone == global_zone);
+	boolean_t curzone = (curproc->p_zone->zone_id == zoneid);
 
 	mutex_enter(&zonehash_lock);
 	if ((zone = zone_find_all_by_id(zoneid)) == NULL) {
@@ -3289,9 +3498,11 @@
 	mutex_exit(&zonehash_lock);
 
 	/*
-	 * If not in the global zone, don't show information about other zones.
+	 * If not in the global zone, don't show information about other zones,
+	 * unless the system is labeled and the local zone's label dominates
+	 * the other zone.
 	 */
-	if (!global && curproc->p_zone != zone) {
+	if (!zone_list_access(zone)) {
 		zone_rele(zone);
 		return (set_errno(EINVAL));
 	}
@@ -3311,12 +3522,29 @@
 			bcopy(zone->zone_rootpath, zonepath, size);
 			zonepath[size - 1] = '\0';
 		} else {
-			/*
-			 * Caller is not in the global zone, just return
-			 * faked-up path for current zone.
-			 */
-			zonepath = "/";
-			size = 2;
+			if (curzone || !is_system_labeled()) {
+				/*
+				 * Caller is not in the global zone.
+				 * if the query is on the current zone
+				 * or the system is not labeled,
+				 * just return faked-up path for current zone.
+				 */
+				zonepath = "/";
+				size = 2;
+			} else {
+				/*
+				 * Return related path for current zone.
+				 */
+				int prefix_len = strlen(zone_prefix);
+				int zname_len = strlen(zone->zone_name);
+
+				size = prefix_len + zname_len + 1;
+				zonepath = kmem_alloc(size, KM_SLEEP);
+				bcopy(zone_prefix, zonepath, prefix_len);
+				bcopy(zone->zone_name, zonepath +
+					prefix_len, zname_len);
+				zonepath[size - 1] = '\0';
+			}
 		}
 		if (bufsize > size)
 			bufsize = size;
@@ -3325,7 +3553,7 @@
 			if (err != 0 && err != ENAMETOOLONG)
 				error = EFAULT;
 		}
-		if (global)
+		if (global || (is_system_labeled() && !curzone))
 			kmem_free(zonepath, size);
 		break;
 
@@ -3388,6 +3616,17 @@
 				error = EFAULT;
 		}
 		break;
+	case ZONE_ATTR_SLBL:
+		size = sizeof (bslabel_t);
+		if (bufsize > size)
+			bufsize = size;
+		if (zone->zone_slabel == NULL)
+			error = EINVAL;
+		else if (buf != NULL &&
+		    copyout(label2bslabel(zone->zone_slabel), buf,
+		    bufsize) != 0)
+			error = EFAULT;
+		break;
 	case ZONE_ATTR_INITPID:
 		size = sizeof (initpid);
 		if (bufsize > size)
@@ -3778,6 +4017,7 @@
  * Systemcall entry point for zone_list(2).
  *
  * Processes running in a (non-global) zone only see themselves.
+ * On labeled systems, they see all zones whose label they dominate.
  */
 static int
 zone_list(zoneid_t *zoneidlist, uint_t *numzones)
@@ -3785,47 +4025,79 @@
 	zoneid_t *zoneids;
 	zone_t *zone;
 	uint_t user_nzones, real_nzones;
-	int error = 0;
-	uint_t i;
+	uint_t domi_nzones;
+	int error;
 
 	if (copyin(numzones, &user_nzones, sizeof (uint_t)) != 0)
 		return (set_errno(EFAULT));
 
 	if (curproc->p_zone != global_zone) {
-		/* just return current zone */
-		real_nzones = 1;
-		zoneids = kmem_alloc(sizeof (zoneid_t), KM_SLEEP);
-		zoneids[0] = curproc->p_zone->zone_id;
+		bslabel_t *mybslab;
+
+		if (!is_system_labeled()) {
+			/* just return current zone */
+			real_nzones = domi_nzones = 1;
+			zoneids = kmem_alloc(sizeof (zoneid_t), KM_SLEEP);
+			zoneids[0] = curproc->p_zone->zone_id;
+		} else {
+			/* return all zones that are dominated */
+			mutex_enter(&zonehash_lock);
+			real_nzones = zonecount;
+			domi_nzones = 0;
+			if (real_nzones > 0) {
+				zoneids = kmem_alloc(real_nzones *
+				    sizeof (zoneid_t), KM_SLEEP);
+				mybslab = label2bslabel(curproc->p_zone->
+				    zone_slabel);
+				for (zone = list_head(&zone_active);
+				    zone != NULL;
+				    zone = list_next(&zone_active, zone)) {
+					if (zone->zone_id == GLOBAL_ZONEID)
+						continue;
+					if (bldominates(mybslab,
+					    label2bslabel(zone->zone_slabel))) {
+						zoneids[domi_nzones++] =
+						    zone->zone_id;
+					}
+				}
+			}
+			mutex_exit(&zonehash_lock);
+		}
 	} else {
 		mutex_enter(&zonehash_lock);
 		real_nzones = zonecount;
-		if (real_nzones) {
+		domi_nzones = 0;
+		if (real_nzones > 0) {
 			zoneids = kmem_alloc(real_nzones * sizeof (zoneid_t),
 			    KM_SLEEP);
-			i = 0;
 			for (zone = list_head(&zone_active); zone != NULL;
 			    zone = list_next(&zone_active, zone))
-				zoneids[i++] = zone->zone_id;
-			ASSERT(i == real_nzones);
+				zoneids[domi_nzones++] = zone->zone_id;
+			ASSERT(domi_nzones == real_nzones);
 		}
 		mutex_exit(&zonehash_lock);
 	}
 
-	if (user_nzones > real_nzones)
-		user_nzones = real_nzones;
-
-	if (copyout(&real_nzones, numzones, sizeof (uint_t)) != 0)
+	/*
+	 * If user has allocated space for fewer entries than we found, then
+	 * return only up to his limit.  Either way, tell him exactly how many
+	 * we found.
+	 */
+	if (domi_nzones < user_nzones)
+		user_nzones = domi_nzones;
+	error = 0;
+	if (copyout(&domi_nzones, numzones, sizeof (uint_t)) != 0) {
 		error = EFAULT;
-	else if (zoneidlist != NULL && user_nzones != 0) {
+	} else if (zoneidlist != NULL && user_nzones != 0) {
 		if (copyout(zoneids, zoneidlist,
 		    user_nzones * sizeof (zoneid_t)) != 0)
 			error = EFAULT;
 	}
 
-	if (real_nzones)
+	if (real_nzones > 0)
 		kmem_free(zoneids, real_nzones * sizeof (zoneid_t));
 
-	if (error)
+	if (error != 0)
 		return (set_errno(error));
 	else
 		return (0);
@@ -3834,7 +4106,8 @@
 /*
  * Systemcall entry point for zone_lookup(2).
  *
- * Non-global zones are only able to see themselves.
+ * Non-global zones are only able to see themselves and (on labeled systems)
+ * the zones they dominate.
  */
 static zoneid_t
 zone_lookup(const char *zone_name)
@@ -3858,15 +4131,20 @@
 	mutex_enter(&zonehash_lock);
 	zone = zone_find_all_by_name(kname);
 	kmem_free(kname, ZONENAME_MAX);
-	if (zone == NULL || zone_status_get(zone) < ZONE_IS_READY ||
-	    (curproc->p_zone != global_zone && curproc->p_zone != zone)) {
-		/* in non-global zone, can only lookup own name */
+	/*
+	 * In a non-global zone, can only lookup global and own name.
+	 * In Trusted Extensions zone label dominance rules apply.
+	 */
+	if (zone == NULL ||
+	    zone_status_get(zone) < ZONE_IS_READY ||
+	    !zone_list_access(zone)) {
 		mutex_exit(&zonehash_lock);
 		return (set_errno(EINVAL));
+	} else {
+		zoneid = zone->zone_id;
+		mutex_exit(&zonehash_lock);
+		return (zoneid);
 	}
-	zoneid = zone->zone_id;
-	mutex_exit(&zonehash_lock);
-	return (zoneid);
 }
 
 static int
@@ -3912,6 +4190,9 @@
 			zs.zfsbufsz = zs32.zfsbufsz;
 			zs.extended_error =
 			    (int *)(unsigned long)zs32.extended_error;
+			zs.match = zs32.match;
+			zs.doi = zs32.doi;
+			zs.label = (const bslabel_t *)(uintptr_t)zs32.label;
 #else
 			panic("get_udatamodel() returned bogus result\n");
 #endif
@@ -3921,7 +4202,8 @@
 		    zs.zone_privs, zs.zone_privssz,
 		    (caddr_t)zs.rctlbuf, zs.rctlbufsz,
 		    (caddr_t)zs.zfsbuf, zs.zfsbufsz,
-		    zs.extended_error));
+		    zs.extended_error, zs.match, zs.doi,
+		    zs.label));
 	case ZONE_BOOT:
 		return (zone_boot((zoneid_t)(uintptr_t)arg1,
 		    (const char *)arg2));
@@ -4261,3 +4543,65 @@
 
 	return (0);
 }
+
+/*
+ * zone_find_by_any_path() -
+ *
+ * kernel-private routine similar to zone_find_by_path(), but which
+ * effectively compares against zone paths rather than zonerootpath
+ * (i.e., the last component of zonerootpaths, which should be "root/",
+ * are not compared.)  This is done in order to accurately identify all
+ * paths, whether zone-visible or not, including those which are parallel
+ * to /root/, such as /dev/, /home/, etc...
+ *
+ * If the specified path does not fall under any zone path then global
+ * zone is returned.
+ *
+ * The treat_abs parameter indicates whether the path should be treated as
+ * an absolute path although it does not begin with "/".  (This supports
+ * nfs mount syntax such as host:any/path.)
+ *
+ * The caller is responsible for zone_rele of the returned zone.
+ */
+zone_t *
+zone_find_by_any_path(const char *path, boolean_t treat_abs)
+{
+	zone_t *zone;
+	int path_offset = 0;
+
+	if (path == NULL) {
+		zone_hold(global_zone);
+		return (global_zone);
+	}
+
+	if (*path != '/') {
+		ASSERT(treat_abs);
+		path_offset = 1;
+	}
+
+	mutex_enter(&zonehash_lock);
+	for (zone = list_head(&zone_active); zone != NULL;
+	    zone = list_next(&zone_active, zone)) {
+		char	*c;
+		size_t	pathlen;
+
+		if (zone == global_zone)	/* skip global zone */
+			continue;
+
+		/* scan backwards to find start of last component */
+		c = zone->zone_rootpath + zone->zone_rootpathlen - 2;
+		do {
+			c--;
+		} while (*c != '/');
+
+		pathlen = c - zone->zone_rootpath + 1;
+		if (strncmp(path, zone->zone_rootpath + path_offset,
+		    pathlen - path_offset) == 0)
+			break;
+	}
+	if (zone == NULL)
+		zone = global_zone;
+	zone_hold(zone);
+	mutex_exit(&zonehash_lock);
+	return (zone);
+}
--- a/usr/src/uts/common/rpc/clnt_clts.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/rpc/clnt_clts.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1428,6 +1427,7 @@
 	int			error;
 	int			retval;
 	zoneid_t		zoneid = rpc_zoneid();
+	cred_t			*cr;
 
 	RPCLOG(1, "endpnt_get: protofmly %s, ", config->knc_protofmly);
 	RPCLOG(1, "rdev %ld\n", config->knc_rdev);
@@ -1633,8 +1633,9 @@
 	/*
 	 * The transport should be opened with sufficient privs
 	 */
+	cr = zone_kcred();
 	error = t_kopen(NULL, config->knc_rdev, FREAD|FWRITE|FNDELAY, &tiptr,
-	    kcred);
+	    cr);
 	if (error) {
 		RPCLOG(1, "endpnt_get: t_kopen: %d\n", error);
 		goto bad;
@@ -1647,14 +1648,14 @@
 	 * Allow the kernel to push the module on behalf of the user.
 	 */
 	error = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"rpcmod", 0,
-			K_TO_K, kcred, &retval);
+	    K_TO_K, cr, &retval);
 	if (error) {
 		RPCLOG(1, "endpnt_get: kstr_push on rpcmod failed %d\n", error);
 		goto bad;
 	}
 
 	error = strioctl(tiptr->fp->f_vnode, RPC_CLIENT, 0, 0, K_TO_K,
-				kcred, &retval);
+	    cr, &retval);
 	if (error) {
 		RPCLOG(1, "endpnt_get: strioctl failed %d\n", error);
 		goto bad;
@@ -1666,7 +1667,7 @@
 	new->e_wq = tiptr->fp->f_vnode->v_stream->sd_wrq->q_next;
 
 	error = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"timod", 0,
-			K_TO_K, kcred, &retval);
+	    K_TO_K, cr, &retval);
 	if (error) {
 		RPCLOG(1, "endpnt_get: kstr_push on timod failed %d\n", error);
 		goto bad;
@@ -1704,8 +1705,8 @@
 			 * reopen with all privileges
 			 */
 			error = t_kopen(NULL, config->knc_rdev,
-					FREAD|FWRITE|FNDELAY,
-					&new->e_tiptr, kcred);
+			    FREAD|FWRITE|FNDELAY,
+			    &new->e_tiptr, cr);
 			if (error) {
 				RPCLOG(1, "endpnt_get: t_kopen: %d\n", error);
 					new->e_tiptr = NULL;
--- a/usr/src/uts/common/rpc/clnt_cots.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/rpc/clnt_cots.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1989,7 +1988,7 @@
 	RPCLOG0(8, "connmgr_get: creating new connection\n");
 	rpcerr->re_status = RPC_TLIERROR;
 
-	i = t_kopen(NULL, device, FREAD|FWRITE|FNDELAY, &tiptr, kcred);
+	i = t_kopen(NULL, device, FREAD|FWRITE|FNDELAY, &tiptr, zone_kcred());
 	if (i) {
 		RPCLOG(1, "connmgr_get: can't open cots device, error %d\n", i);
 		rpcerr->re_errno = i;
--- a/usr/src/uts/common/rpc/svc.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/rpc/svc.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -212,6 +211,7 @@
 #include <sys/vtrace.h>
 #include <sys/zone.h>
 #include <nfs/nfs.h>
+#include <sys/tsol/label_macro.h>
 
 #define	RQCRED_SIZE	400	/* this size is excessive */
 
@@ -1305,6 +1305,8 @@
 	    "svc_getreq_start:");
 
 	ASSERT(clone_xprt->xp_master != NULL);
+	ASSERT(!is_system_labeled() || DB_CRED(mp) != NULL ||
+	    mp->b_datap->db_type != M_DATA);
 
 	/*
 	 * Firstly, allocate the authentication parameters' storage
@@ -1326,6 +1328,28 @@
 	r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
 
 	/*
+	 * underlying transport recv routine may modify mblk data
+	 * and make it difficult to extract label afterwards. So
+	 * get the label from the raw mblk data now.
+	 */
+	if (is_system_labeled()) {
+		mblk_t *lmp;
+
+		r.rq_label = kmem_alloc(sizeof (bslabel_t), KM_SLEEP);
+		if (DB_CRED(mp) != NULL)
+			lmp = mp;
+		else {
+			ASSERT(mp->b_cont != NULL);
+			lmp = mp->b_cont;
+			ASSERT(DB_CRED(lmp) != NULL);
+		}
+		bcopy(label2bslabel(crgetlabel(DB_CRED(lmp))), r.rq_label,
+		    sizeof (bslabel_t));
+	} else {
+		r.rq_label = NULL;
+	}
+
+	/*
 	 * Now receive a message from the transport.
 	 */
 	if (SVC_RECV(clone_xprt, mp, &msg)) {
@@ -1410,6 +1434,9 @@
 		}
 	}
 
+	if (r.rq_label != NULL)
+		kmem_free(r.rq_label, sizeof (bslabel_t));
+
 	/*
 	 * Free authentication parameters' storage
 	 */
@@ -1442,7 +1469,6 @@
 	/* Fre credentials from crget() */
 	if (clone_xprt->xp_cred)
 		crfree(clone_xprt->xp_cred);
-
 	kmem_free(clone_xprt, sizeof (SVCXPRT));
 }
 
@@ -1480,6 +1506,7 @@
 	/* Restore per-thread fields (xp_cred) */
 	clone_xprt->xp_cred = cred;
 
+
 	/*
 	 * NOTICE: There is no transport-type specific code now.
 	 *	   If you want to add a transport-type specific cloning code
@@ -2379,6 +2406,9 @@
 
 	TRACE_0(TR_FAC_KRPC, TR_SVC_QUEUEREQ_START, "svc_queuereq_start");
 
+	ASSERT(!is_system_labeled() || DB_CRED(mp) != NULL ||
+	    mp->b_datap->db_type != M_DATA);
+
 	/*
 	 * Step 1.
 	 * Grab the transport's request lock and put
--- a/usr/src/uts/common/rpc/svc.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/rpc/svc.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -44,6 +43,7 @@
 #include <rpc/rpc_msg.h>
 #include <sys/tihdr.h>
 #include <sys/poll.h>
+#include <sys/tsol/label.h>
 
 #ifdef	_KERNEL
 #include <rpc/svc_auth.h>
@@ -110,6 +110,7 @@
 	struct opaque_auth rq_cred;	/* raw creds from the wire */
 	caddr_t		rq_clntcred;	/* read only cooked cred */
 	SVCXPRT		*rq_xprt;	/* associated transport */
+	bslabel_t	*rq_label;	/* TSOL label of the request */
 };
 
 #ifdef _KERNEL
@@ -991,6 +992,8 @@
 extern int svc_dg_enablecache();
 #endif	/* __STDC__ */
 
+extern boolean_t is_multilevel(rpcprog_t);
+
 #ifdef	PORTMAP
 /* For backward compatibility */
 #include <rpc/svc_soc.h>
--- a/usr/src/uts/common/sys/Makefile	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/Makefile	Fri Mar 24 12:29:20 2006 -0800
@@ -841,6 +841,13 @@
 	rsmpi_driver.h	\
 	rsmka_path_int.h
 
+TSOLHDRS=		\
+	label.h		\
+	label_macro.h	\
+	priv.h		\
+	tndb.h		\
+	tsyscall.h
+
 I1394HDRS=		\
 	cmd1394.h	\
 	id1394.h	\
@@ -939,7 +946,8 @@
 	$(UGENHDRS:%.h=usb/clients/ugen/%.check)   \
 	$(USBHDRS:%.h=usb/%.check)                      \
 	$(I1394HDRS:%.h=1394/%.check)			\
-	$(RSMHDRS:%.h=rsm/%.check)
+	$(RSMHDRS:%.h=rsm/%.check)			\
+	$(TSOLHDRS:%.h=tsol/%.check)
 
 
 .KEEP_STATE:
@@ -984,6 +992,7 @@
 	$(ROOTHOTPLUGHDRS)	\
 	$(ROOTHOTPLUGPCIHDRS)	\
 	$(ROOTRSMHDRS)		\
+	$(ROOTTSOLHDRS)		\
 	$($(MACH)_ROOTHDRS)
 
 
@@ -1029,6 +1038,7 @@
 	$(ROOTHOTPLUGHDRS)	\
 	$(ROOTHOTPLUGPCIHDRS)	\
 	$(ROOTRSMHDRS)		\
+	$(ROOTTSOLHDRS)		\
 	$($(MACH)_ROOTHDRS)
 
 all_h: $(GENHDRS)
--- a/usr/src/uts/common/sys/Makefile.syshdrs	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/Makefile.syshdrs	Fri Mar 24 12:29:20 2006 -0800
@@ -111,6 +111,9 @@
 rsm/%.check:	rsm/%.h
 	$(DOT_H_CHECK)
 
+tsol/%.check:	tsol/%.h
+	$(DOT_H_CHECK)
+
 ROOTDIR=	$(ROOT)/usr/include/sys
 
 ROOTDKTPDIR=	$(ROOTDIR)/dktp
@@ -162,6 +165,7 @@
 	$(ROOTDIR)/usb/clients/ugen  \
 	$(ROOTDIR)/1394         \
 	$(ROOTDIR)/rsm		\
+	$(ROOTDIR)/tsol		\
 	$($(MACH)_ROOTDIRS)
 
 
@@ -234,6 +238,7 @@
 ROOTHOTPLUGHDRS= $(HOTPLUGHDRS:%=$(ROOTDIR)/hotplug/%)
 ROOTHOTPLUGPCIHDRS= $(HOTPLUGPCIHDRS:%=$(ROOTDIR)/hotplug/pci/%)
 
+ROOTTSOLHDRS= $(TSOLHDRS:%=$(ROOTDIR)/tsol/%)
 
 sparc_ROOTHDRS=	$(ROOTSDKTPHDRS) $(ROOTSCSICADHDRS) $(ROOTSCSITARGETSHDRS) \
 		$(ROOTFCHDRS) $(ROOTUSBHDRS) $(ROOTUSBHUBDHDRS) $(ROOTPCMCIAHDRS) \
@@ -340,6 +345,9 @@
 $(ROOTDIR)/rsm/%:	rsm/%
 	$(INS.file)
 
+$(ROOTDIR)/tsol/%:	tsol/%
+	$(INS.file)
+
 $(ROOTDIRS):
 	$(INS.dir)
 
--- a/usr/src/uts/common/sys/cred.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/cred.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -81,6 +80,7 @@
 extern int hasprocperm(const cred_t *, const cred_t *);
 extern int prochasprocperm(struct proc *, struct proc *, const cred_t *);
 extern int crcmp(const cred_t *, const cred_t *);
+extern cred_t *zone_kcred(void);
 
 extern uid_t crgetuid(const cred_t *);
 extern uid_t crgetruid(const cred_t *);
@@ -91,6 +91,7 @@
 extern zoneid_t crgetzoneid(const cred_t *);
 extern projid_t crgetprojid(const cred_t *);
 
+
 extern const struct auditinfo_addr *crgetauinfo(const cred_t *);
 extern struct auditinfo_addr *crgetauinfo_modifiable(cred_t *);
 
@@ -120,6 +121,7 @@
  */
 struct zone;
 extern void crsetzone(cred_t *, struct zone *);
+extern struct zone *crgetzone(const cred_t *);
 
 /*
  * Private interface for setting project id in credential.
@@ -136,6 +138,13 @@
  */
 extern void cred2prcred(const cred_t *, struct prcred *);
 
+/*
+ * Private interfaces for Rampart Trusted Solaris.
+ */
+struct ts_label_s;
+extern struct ts_label_s *crgetlabel(const cred_t *);
+extern boolean_t crisremote(const cred_t *);
+
 #endif	/* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/sys/cred_impl.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/cred_impl.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,6 +62,7 @@
 #if defined(_KERNEL) || defined(_KMEMUSER)
 
 struct zone;		/* forward reference */
+struct ts_label_s;	/* forward reference */
 
 struct cred {
 	uint_t		cr_ref;		/* reference count */
@@ -77,6 +77,7 @@
 	cred_priv_t	cr_priv;	/* privileges */
 	projid_t	cr_projid;	/* project */
 	struct zone	*cr_zone;	/* pointer to per-zone structure */
+	struct ts_label_s *cr_label;	/* pointer to the effective label */
 	gid_t		cr_groups[1];	/* cr_groups size not fixed */
 					/* audit info is defined dynamically */
 					/* and valid only when audit enabled */
--- a/usr/src/uts/common/sys/policy.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/policy.h	Fri Mar 24 12:29:20 2006 -0800
@@ -102,10 +102,13 @@
 int secpolicy_lock_memory(const cred_t *);
 int secpolicy_modctl(const cred_t *, int);
 int secpolicy_net(const cred_t *, int, boolean_t);
+int secpolicy_net_bindmlp(const cred_t *);
 int secpolicy_net_config(const cred_t *, boolean_t);
 int secpolicy_net_icmpaccess(const cred_t *);
+int secpolicy_net_mac_aware(const cred_t *);
 int secpolicy_net_privaddr(const cred_t *, in_port_t);
 int secpolicy_net_rawaccess(const cred_t *);
+boolean_t secpolicy_net_reply_equal(const cred_t *);
 int secpolicy_newproc(const cred_t *);
 int secpolicy_nfs(const cred_t *);
 int secpolicy_pcfs_modify_bootpartition(const cred_t *);
--- a/usr/src/uts/common/sys/priv.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/priv.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -133,7 +132,11 @@
 #define	PRIV_AWARE			0x0002		/* Is privilege aware */
 #define	PRIV_AWARE_INHERIT		0x0004		/* Inherit awareness */
 #define	__PROC_PROTECT			0x0008		/* Private */
-#define	PRIV_USER			(PRIV_DEBUG)	/* User settable */
+#define	NET_MAC_AWARE			0x0010		/* Is MAC aware */
+#define	NET_MAC_AWARE_INHERIT		0x0020		/* Inherit MAC aware */
+
+/* user-settable flags: */
+#define	PRIV_USER	(PRIV_DEBUG | NET_MAC_AWARE | NET_MAC_AWARE_INHERIT)
 
 /*
  * Header of the privilege info data structure; multiple structures can
@@ -228,6 +231,9 @@
 extern void priv_adjust_PA(cred_t *);
 extern boolean_t priv_can_clear_PA(const cred_t *);
 
+extern int setpflags(uint_t, uint_t, cred_t *);
+extern uint_t getpflags(uint_t, const cred_t *);
+
 #endif /* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/sys/socket.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/socket.h	Fri Mar 24 12:29:20 2006 -0800
@@ -142,6 +142,8 @@
 #define	SO_ERROR	0x1007		/* get error status and clear */
 #define	SO_TYPE		0x1008		/* get socket type */
 #define	SO_PROTOTYPE	0x1009		/* get/set protocol type */
+#define	SO_ANON_MLP	0x100a		/* create MLP on anonymous bind */
+#define	SO_MAC_EXEMPT	0x100b		/* allow dominated unlabeled peers */
 
 /* "Socket"-level control message types: */
 #define	SCM_RIGHTS	0x1010		/* access rights (array of int) */
--- a/usr/src/uts/common/sys/strsun.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/strsun.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,6 +54,9 @@
 #define	MBLKIN(mp, off, len) (((off) <= MBLKL(mp)) && \
 			(((mp)->b_rptr + (off) + (len)) <= (mp)->b_wptr))
 
+#define	MBLK_GETLABEL(mp) \
+	(DB_CRED(mp) != NULL ? crgetlabel(DB_CRED(mp)) : NULL)
+
 #ifdef	_KERNEL
 extern void	mcopyin(mblk_t *, void *, size_t, void *);
 extern void	mcopyout(mblk_t *, void *, size_t, void *, mblk_t *);
--- a/usr/src/uts/common/sys/syscall.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/syscall.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -395,7 +394,7 @@
 	 *	port_dispatch(...) :: portfs(PORT_DISPATCH, ...)
 	 */
 #define	SYS_pollsys		183
-#define	SYS_tsolsys		184
+#define	SYS_labelsys		184
 #define	SYS_acl			185
 #define	SYS_auditsys		186
 #define	SYS_processor_bind	187
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/label.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,146 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_TSOL_LABEL_H
+#define	_SYS_TSOL_LABEL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/tsol/label_macro.h>
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Binary Label Structure Definitions */
+
+typedef	struct _mac_label_impl	m_label_t;
+
+typedef m_label_t	blevel_t,		/* compatibility */
+			bslabel_t,		/* Sensitivity Label */
+			bclear_t;		/* Clearance */
+
+typedef struct _tsol_binary_level_lrange {	/* Level Range */
+	m_label_t *lower_bound;
+	m_label_t *upper_bound;
+} m_range_t;
+
+typedef	m_range_t	blrange_t;
+
+#define	NMLP_MAX	0x10
+#define	NSLS_MAX	0x4
+
+typedef m_label_t blset_t[NSLS_MAX];
+
+typedef struct tsol_mlp_s {
+	uchar_t mlp_ipp;
+	uint16_t mlp_port;
+	uint16_t mlp_port_upper;
+} tsol_mlp_t;
+
+/* Procedure Interface Definitions available to user and kernel */
+
+extern int	bltype(const void *, uint8_t);
+extern int	blequal(const m_label_t *, const m_label_t *);
+extern int	bldominates(const m_label_t *, const m_label_t *);
+extern int	blstrictdom(const m_label_t *, const m_label_t *);
+extern int	blinrange(const m_label_t *, const m_range_t *);
+extern void	blmaximum(m_label_t *, const m_label_t *);
+extern void	blminimum(m_label_t *, const m_label_t *);
+extern void	bsllow(m_label_t *);
+extern void	bslhigh(m_label_t *);
+extern void	bclearlow(m_label_t *);
+extern void	bclearhigh(m_label_t *);
+extern void	bslundef(m_label_t *);
+extern void	bclearundef(m_label_t *);
+extern void	setbltype(void *, uint8_t);
+extern boolean_t	bisinvalid(const void *);
+
+#ifdef	_KERNEL
+typedef struct tsol_mlp_entry_s {
+	struct tsol_mlp_entry_s *mlpe_next, *mlpe_prev;
+	zoneid_t mlpe_zoneid;
+	tsol_mlp_t mlpe_mlp;
+} tsol_mlp_entry_t;
+
+typedef struct tsol_mlp_list_s {
+	krwlock_t mlpl_rwlock;
+	tsol_mlp_entry_t *mlpl_first, *mlpl_last;
+} tsol_mlp_list_t;
+
+typedef	struct ts_label_s {
+	uint_t		tsl_ref;	/* Reference count */
+	uint32_t	tsl_doi;	/* Domain of Interpretation */
+	uint32_t	tsl_flags;	/* TSLF_* below */
+	m_label_t	tsl_label;	/* Actual label */
+} ts_label_t;
+
+#define	DEFAULT_DOI 1
+
+#define	TSLF_UNLABELED	0x00000001	/* source was unlabeled */
+
+#define	CR_SL(cr)	(label2bslabel(crgetlabel(cr)))
+
+extern ts_label_t	*l_admin_low;
+extern ts_label_t	*l_admin_high;
+extern uint32_t		default_doi;
+extern int		sys_labeling;
+
+extern void		label_init(void);
+extern ts_label_t	*labelalloc(const m_label_t *, uint32_t, int);
+extern void		label_hold(ts_label_t *);
+extern void		label_rele(ts_label_t *);
+extern m_label_t	*label2bslabel(ts_label_t *);
+extern uint32_t		label2doi(ts_label_t *);
+extern boolean_t	label_equal(const ts_label_t *, const ts_label_t *);
+extern cred_t 		*newcred_from_bslabel(m_label_t *, uint32_t, int);
+extern cred_t 		*copycred_from_bslabel(cred_t *, m_label_t *,
+			    uint32_t, int);
+extern ts_label_t	*getflabel(vnode_t *);
+extern int		getlabel(const char *, m_label_t *);
+extern int		fgetlabel(int, m_label_t *);
+extern int		_blinrange(const m_label_t *, const brange_t *);
+extern int		blinlset(const m_label_t *, const blset_t);
+extern ts_label_t	*nfs4_getflabel(vnode_t *);
+
+/*
+ * The use of '!!' here prevents users from referencing this function-like
+ * macro as though it were an l-value, and in normal use is optimized away
+ * by the compiler.
+ */
+#define	is_system_labeled()	(!!(sys_labeling > 0))
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* !_SYS_TSOL_LABEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/label_macro.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,356 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_LABEL_MACRO_H
+#define	_LABEL_MACRO_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* PRIVATE ONLY TO THE LABEL LIBRARY.  DO NOT USE ELSEWHERE */
+
+/* Actual Binary Label Structure Definitions */
+
+typedef int16_t	_Classification;
+typedef struct {
+	union {
+		uint8_t		class_ar[2];
+		_Classification	class_chunk;
+	} class_u;
+} Classification_t;
+
+typedef struct {
+	uint32_t c1;
+	uint32_t c2;
+	uint32_t c3;
+	uint32_t c4;
+	uint32_t c5;
+	uint32_t c6;
+	uint32_t c7;
+	uint32_t c8;
+} Compartments_t;
+
+typedef struct {
+	uint32_t m1;
+	uint32_t m2;
+	uint32_t m3;
+	uint32_t m4;
+	uint32_t m5;
+	uint32_t m6;
+	uint32_t m7;
+	uint32_t m8;
+} Markings_t;
+
+typedef struct _mac_label_impl {
+	uint8_t id;		/* Magic to say label type */
+	uint8_t _c_len;		/* Number of Compartment words */
+	Classification_t classification;
+	Compartments_t compartments;
+} _mac_label_impl_t;
+
+typedef _mac_label_impl_t	_blevel_impl_t,		/* compatibility */
+				_bslabel_impl_t,	/* Sensitivity Label */
+				_bclear_impl_t;		/* Clearance */
+
+typedef struct _binary_information_label_impl {	/* Information Label */
+	_mac_label_impl_t	binformation_level;
+	Markings_t markings;
+} _bilabel_impl_t;
+
+typedef struct _binary_cmw_label_impl {		/* CMW Label */
+	_bslabel_impl_t bcl_sensitivity_label;
+	_bilabel_impl_t bcl_information_label;
+} _bclabel_impl_t;
+
+typedef struct _binary_level_range_impl {	/* Level Range */
+	_mac_label_impl_t lower_bound;
+	_mac_label_impl_t upper_bound;
+} _brange_impl_t, brange_t;
+
+/* Label Identifier Types */
+
+#define	SUN_MAC_ID	0x41	/* MAC label, legacy SUN_SL_ID */
+#define	SUN_UCLR_ID	0x49	/* User Clearance, legacy SUN_CLR_ID */
+
+#define	_C_LEN		8	/* number of compartments words */
+
+/* m_label_t macros */
+#define	_MTYPE(l, t) \
+	(((_mac_label_impl_t *)(l))->id == (t))
+
+#define	_MSETTYPE(l, t) \
+	(((_mac_label_impl_t *)(l))->id = (t))
+
+#define	_MGETTYPE(l)	(((_mac_label_impl_t *)(l))->id)
+
+#define	_MEQUAL(l1, l2) \
+	(LCLASS(l1) == LCLASS(l2) && \
+	(l1)->_comps.c1 == (l2)->_comps.c1 && \
+	(l1)->_comps.c2 == (l2)->_comps.c2 && \
+	(l1)->_comps.c3 == (l2)->_comps.c3 && \
+	(l1)->_comps.c4 == (l2)->_comps.c4 && \
+	(l1)->_comps.c5 == (l2)->_comps.c5 && \
+	(l1)->_comps.c6 == (l2)->_comps.c6 && \
+	(l1)->_comps.c7 == (l2)->_comps.c7 && \
+	(l1)->_comps.c8 == (l2)->_comps.c8)
+
+#define	SUN_INVALID_ID	0	/* uninitialized label */
+#define	SUN_CMW_ID	0x83	/* 104 - total bytes in CMW Label */
+#define	SUN_SL_ID	0x41	/* 36 - total bytes in Sensitivity Label */
+#define	SUN_SL_UN	0xF1	/* undefined Sensitivity Label */
+#define	SUN_IL_ID	0x42	/* 68 - total bytes in Information Label */
+#define	SUN_IL_UN	0x73	/* undefined Information Label */
+#define	SUN_CLR_ID	0x49	/* 36 - total bytes in Clearance */
+#define	SUN_CLR_UN	0xF9	/* undefined Clearance */
+
+#define	_bcl_sl		bcl_sensitivity_label
+#define	_bcl_il		bcl_information_label
+#define	_bslev_il	binformation_level
+
+#define	_lclass		classification
+#ifdef	_BIG_ENDIAN
+#define	LCLASS(slp)	((slp)->_lclass.class_u.class_chunk)
+#define	LCLASS_SET(slp, l)	((slp)->_lclass.class_u.class_chunk = (l))
+#else
+#define	LCLASS(slp)	\
+	((_Classification)(((slp)->_lclass.class_u.class_ar[0] << 8) | \
+	(slp)->_lclass.class_u.class_ar[1]))
+#define	LCLASS_SET(slp, l)	\
+	((slp)->_lclass.class_u.class_ar[0] = (uint8_t)((l)>> 8), \
+	(slp)->_lclass.class_u.class_ar[1] = (uint8_t)(l))
+#endif	/* _BIG_ENDIAN */
+#define	_comps		compartments
+
+#define	_iid		_bslev_il.id
+#define	_i_c_len		_bslev_il._c_len
+#define	_iclass		_bslev_il._lclass
+#ifdef	_BIG_ENDIAN
+#define	ICLASS(ilp)	((ilp)->_iclass.class_u.class_chunk)
+#define	ICLASS_SET(ilp, l)	((ilp)->_iclass.class_u.class_chunk = (l))
+#else
+#define	ICLASS(ilp)	\
+	((_Classification)(((ilp)->_iclass.class_u.class_ar[0] << 8) | \
+	(ilp)->_iclass.class_u.class_ar[1]))
+#define	ICLASS_SET(ilp, l)	\
+	((ilp)->_iclass.class_u.class_ar[0] = (uint8_t)((l)>> 8), \
+	(ilp)->_iclass.class_u.class_ar[1] = (uint8_t)(l))
+#endif	/* _BIG_ENDIAN */
+#define	_icomps		_bslev_il._comps
+#define	_imarks		markings
+
+/* Manifest Constant Values */
+
+#define	LOW_CLASS	0	/* Admin_Low classification value */
+#define	HIGH_CLASS	0x7FFF	/* Admin_High classification value */
+#define	EMPTY_SET	0	/* Empty compartments and markings set */
+#define	UNIVERSAL_SET	0xFFFFFFFFU	/* Universal compartments and */
+					/* markings set */
+
+/* Construct initial labels */
+
+#define	_LOW_LABEL(l, t) \
+	((l)->id = t, (l)->_c_len = _C_LEN, LCLASS_SET(l, LOW_CLASS), \
+	(l)->_comps.c1 = (l)->_comps.c2 = (l)->_comps.c3 = (l)->_comps.c4 = \
+	(l)->_comps.c5 = (l)->_comps.c6 = (l)->_comps.c7 = (l)->_comps.c8 = \
+	EMPTY_SET)
+
+#define	_HIGH_LABEL(l, t) \
+	((l)->id = t, (l)->_c_len = _C_LEN, LCLASS_SET(l, HIGH_CLASS), \
+	(l)->_comps.c1 = (l)->_comps.c2 = (l)->_comps.c3 = (l)->_comps.c4 = \
+	(l)->_comps.c5 = (l)->_comps.c6 = (l)->_comps.c7 = (l)->_comps.c8 = \
+	UNIVERSAL_SET)
+
+/* Macro equivalents */
+
+/* Is this memory a properly formatted label of type t? */
+#define	BLTYPE(l, t) \
+	((t) == SUN_CMW_ID ? \
+	(((_bclabel_impl_t *)(l))->_bcl_sl.id == SUN_SL_ID || \
+	((_bclabel_impl_t *)(l))->_bcl_sl.id == SUN_SL_UN) && \
+	(((_bclabel_impl_t *)(l))->_bcl_il._iid == SUN_IL_ID || \
+	((_bclabel_impl_t *)(l))->_bcl_il._iid == SUN_IL_UN) : \
+	((_mac_label_impl_t *)(l))->id == (t))
+
+/* Are the levels of these labels equal? */
+#define	BLEQUAL(l1, l2) \
+	_BLEQUAL((_mac_label_impl_t *)(l1), (_mac_label_impl_t *)(l2))
+
+#define	_BLEQUAL(l1, l2) \
+	(LCLASS(l1) == LCLASS(l2) && \
+	(l1)->_comps.c1 == (l2)->_comps.c1 && \
+	(l1)->_comps.c2 == (l2)->_comps.c2 && \
+	(l1)->_comps.c3 == (l2)->_comps.c3 && \
+	(l1)->_comps.c4 == (l2)->_comps.c4 && \
+	(l1)->_comps.c5 == (l2)->_comps.c5 && \
+	(l1)->_comps.c6 == (l2)->_comps.c6 && \
+	(l1)->_comps.c7 == (l2)->_comps.c7 && \
+	(l1)->_comps.c8 == (l2)->_comps.c8)
+
+/* Does the level of l1 dominate that of l2? */
+#define	BLDOMINATES(l1, l2) \
+	_BLDOMINATES((_mac_label_impl_t *)(l1), (_mac_label_impl_t *)(l2))
+
+#define	_BLDOMINATES(l1, l2) (LCLASS(l1) >= LCLASS(l2) && \
+	(l2)->_comps.c1 == ((l1)->_comps.c1 & (l2)->_comps.c1) && \
+	(l2)->_comps.c2 == ((l1)->_comps.c2 & (l2)->_comps.c2) && \
+	(l2)->_comps.c3 == ((l1)->_comps.c3 & (l2)->_comps.c3) && \
+	(l2)->_comps.c4 == ((l1)->_comps.c4 & (l2)->_comps.c4) && \
+	(l2)->_comps.c5 == ((l1)->_comps.c5 & (l2)->_comps.c5) && \
+	(l2)->_comps.c6 == ((l1)->_comps.c6 & (l2)->_comps.c6) && \
+	(l2)->_comps.c7 == ((l1)->_comps.c7 & (l2)->_comps.c7) && \
+	(l2)->_comps.c8 == ((l1)->_comps.c8 & (l2)->_comps.c8))
+
+/* Does the level of l1 strictly dominate that of l2? */
+#define	BLSTRICTDOM(l1, l2) (!BLEQUAL(l1, l2) && BLDOMINATES(l1, l2))
+
+/* Is the level of l within the range r? */
+#define	BLINRANGE(l, r)\
+	(BLDOMINATES((l), &((r)->lower_bound)) && \
+	BLDOMINATES(&((r)->upper_bound), (l)))
+
+/* Least Upper Bound level l1 and l2 replacing l1 with the result. */
+#define	BLMAXIMUM(l1, l2) \
+	_BLMAXIMUM((_mac_label_impl_t *)(l1), (_mac_label_impl_t *)(l2))
+
+#define	_BLMAXIMUM(l1, l2)\
+	(((l1)->_lclass = (LCLASS(l1) < LCLASS(l2)) ? \
+	(l2)->_lclass : (l1)->_lclass), \
+	(l1)->_comps.c1 |= (l2)->_comps.c1, \
+	(l1)->_comps.c2 |= (l2)->_comps.c2, \
+	(l1)->_comps.c3 |= (l2)->_comps.c3, \
+	(l1)->_comps.c4 |= (l2)->_comps.c4, \
+	(l1)->_comps.c5 |= (l2)->_comps.c5, \
+	(l1)->_comps.c6 |= (l2)->_comps.c6, \
+	(l1)->_comps.c7 |= (l2)->_comps.c7, \
+	(l1)->_comps.c8 |= (l2)->_comps.c8)
+
+/* Greatest Lower Bound level l1 and l2 replacing l1 with the result. */
+#define	BLMINIMUM(l1, l2) \
+	_BLMINIMUM((_mac_label_impl_t *)(l1), (_mac_label_impl_t *)(l2))
+
+#define	_BLMINIMUM(l1, l2)\
+	(((l1)->_lclass = (LCLASS(l1) > LCLASS(l2)) ? \
+	(l2)->_lclass : (l1)->_lclass), \
+	(l1)->_comps.c1 &= (l2)->_comps.c1, \
+	(l1)->_comps.c2 &= (l2)->_comps.c2, \
+	(l1)->_comps.c3 &= (l2)->_comps.c3, \
+	(l1)->_comps.c4 &= (l2)->_comps.c4, \
+	(l1)->_comps.c5 &= (l2)->_comps.c5, \
+	(l1)->_comps.c6 &= (l2)->_comps.c6, \
+	(l1)->_comps.c7 &= (l2)->_comps.c7, \
+	(l1)->_comps.c8 &= (l2)->_comps.c8)
+
+/* Create Manifest Labels */
+
+/* Write a System_Low CMW Label into this memory. */
+#define	BCLLOW(l) (BSLLOW(BCLTOSL(l)), BILLOW(BCLTOIL(l)))
+
+/* Write a System_Low Sensitivity Label into this memory. */
+#define	BSLLOW(l) _BSLLOW((_bslabel_impl_t *)(l))
+
+#define	_BSLLOW(l) \
+	((l)->id = SUN_SL_ID, (l)->_c_len = _C_LEN, LCLASS_SET(l, LOW_CLASS), \
+	(l)->_comps.c1 = (l)->_comps.c2 = (l)->_comps.c3 = (l)->_comps.c4 = \
+	(l)->_comps.c5 = (l)->_comps.c6 = (l)->_comps.c7 = (l)->_comps.c8 = \
+	EMPTY_SET)
+
+/* Write a System_High Sensitivity Label into this memory. */
+#define	BSLHIGH(l) _BSLHIGH((_bslabel_impl_t *)(l))
+
+#define	_BSLHIGH(l) \
+	((l)->id = SUN_SL_ID, (l)->_c_len = _C_LEN, LCLASS_SET(l, HIGH_CLASS), \
+	(l)->_comps.c1 = (l)->_comps.c2 = (l)->_comps.c3 = (l)->_comps.c4 = \
+	(l)->_comps.c5 = (l)->_comps.c6 = (l)->_comps.c7 = (l)->_comps.c8 = \
+	UNIVERSAL_SET)
+
+/* Write a System_Low Information Label into this memory. */
+#define	BILLOW(l) _BILLOW((_bilabel_impl_t *)(l))
+
+#define	_BILLOW(l) \
+	((l)->_iid = SUN_IL_ID, (l)->_i_c_len = _C_LEN, \
+	ICLASS_SET(l, LOW_CLASS), \
+	(l)->_icomps.c1 = (l)->_icomps.c2 = (l)->_icomps.c3 = \
+	(l)->_icomps.c4 = (l)->_icomps.c5 = (l)->_icomps.c6 = \
+	(l)->_icomps.c7 = (l)->_icomps.c8 = EMPTY_SET, \
+	(l)->_imarks.m1 = (l)->_imarks.m2 = (l)->_imarks.m3 = \
+	(l)->_imarks.m4 = (l)->_imarks.m5 = (l)->_imarks.m6 = \
+	(l)->_imarks.m7 = (l)->_imarks.m8 = EMPTY_SET)
+
+
+/* Write a System_Low Sensitivity Label into this memory. */
+#define	BCLEARLOW(l) _BCLEARLOW((_bclear_impl_t *)(l))
+
+#define	_BCLEARLOW(c) \
+	((c)->id = SUN_CLR_ID, (c)->_c_len = _C_LEN, \
+	LCLASS_SET(c, LOW_CLASS), \
+	(c)->_comps.c1 = (c)->_comps.c2 = (c)->_comps.c3 = (c)->_comps.c4 = \
+	(c)->_comps.c5 = (c)->_comps.c6 = (c)->_comps.c7 = (c)->_comps.c8 = \
+	EMPTY_SET)
+
+/* Write a System_High Sensitivity Label into this memory. */
+#define	BCLEARHIGH(l) _BCLEARHIGH((_bclear_impl_t *)(l))
+
+#define	_BCLEARHIGH(c) \
+	((c)->id = SUN_CLR_ID, (c)->_c_len = _C_LEN, \
+	LCLASS_SET(c, HIGH_CLASS), \
+	(c)->_comps.c1 = (c)->_comps.c2 = (c)->_comps.c3 = (c)->_comps.c4 = \
+	(c)->_comps.c5 = (c)->_comps.c6 = (c)->_comps.c7 = (c)->_comps.c8 = \
+	UNIVERSAL_SET)
+
+/* Write an undefined Sensitivity Label into this memory. */
+#define	BSLUNDEF(l) (((_bslabel_impl_t *)(l))->id = SUN_SL_UN)
+
+/* Write an undefined Clearance into this memory. */
+#define	BCLEARUNDEF(c) (((_bclear_impl_t *)(c))->id = SUN_CLR_UN)
+
+/* Retrieve the Sensitivity Label portion of a CMW Label */
+#define	BCLTOSL(l) ((bslabel_t *)&((_bclabel_impl_t *)(l))->_bcl_sl)
+
+/* Retrieve the Information Label portion of a CMW Label */
+#define	BCLTOIL(l) ((_bilabel_impl_t *)&((_bclabel_impl_t *)(l))->_bcl_il)
+
+/* Copy the Sensitivity Label portion from a CMW Label */
+#define	GETCSL(l1, l2) \
+	(*((_bslabel_impl_t *)(l1)) = ((_bclabel_impl_t *)(l2))->_bcl_sl)
+
+/* Replace the Sensitivity Label portion of a CMW Label */
+#define	SETCSL(l1, l2) \
+	(((_bclabel_impl_t *)(l1))->_bcl_sl = *((_bslabel_impl_t *)(l2)))
+
+/* Set type of this memory to the label type 't' */
+#define	SETBLTYPE(l, t) (((_bclabel_impl_t *)(l))->_bcl_sl.id = (t))
+
+#define	GETBLTYPE(l)	(((const _bclabel_impl_t *)(l))->_bcl_sl.id)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* !_LABEL_MACRO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/priv.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_TSOL_PRIV_H
+#define	_SYS_TSOL_PRIV_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/priv.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef enum priv_ftype {
+	PRIV_ALLOWED,
+	PRIV_FORCED
+} priv_ftype_t;
+
+/*
+ * Privilege macros.
+ */
+
+/*
+ * PRIV_ASSERT(a, b) setst.privilege "b" in privilege set "a".
+ */
+#define	PRIV_ASSERT(a, b) (priv_addset(a, b))
+
+/*
+ * PRIV_CLEAR(a,b) clearst.privilege "b" in privilege set "a".
+ */
+#define	PRIV_CLEAR(a, b) (priv_delset(a, b))
+
+/*
+ * PRIV_EQUAL(set_a, set_b) is true if set_a and set_b are identical.
+ */
+#define	PRIV_EQUAL(a, b) (priv_isequalset(a, b))
+#define	PRIV_EMPTY(a) (priv_emptyset(a))
+#define	PRIV_FILL(a) (priv_fillset(a))
+
+/*
+ * PRIV_ISASSERT tests if privilege 'b' is asserted in privilege set 'a'.
+ */
+#define	PRIV_ISASSERT(a, b) (priv_ismember(a, b))
+#define	PRIV_ISEMPTY(a) (priv_isemptyset(a))
+#define	PRIV_ISFULL(a) (priv_isfullset(a))
+
+/*
+ * This macro returns 1 if all privileges asserted in privilege set "a"
+ * are also asserted in privilege set "b" (i.e. if a is a subset of b)
+ */
+#define	PRIV_ISSUBSET(a, b) (priv_issubset(a, b))
+
+/*
+ * Takes intersection of "a" and "b" and stores in "b".
+ */
+#define	PRIV_INTERSECT(a, b) (priv_intersect(a, b))
+
+/*
+ * Replaces "a" with inverse of "a".
+ */
+#define	PRIV_INVERSE(a)  (priv_inverse(a))
+
+/*
+ * Takes union of "a" and "b" and stores in "b".
+ */
+#define	PRIV_UNION(a, b) (priv_union(a, b))
+
+
+#define	PRIV_FILE_UPGRADE_SL	((const char *)"file_upgrade_sl")
+#define	PRIV_FILE_DOWNGRADE_SL	((const char *)"file_downgrade_sl")
+#
+#define	PRIV_PROC_AUDIT_TCB	((const char *)"proc_audit")
+#define	PRIV_PROC_AUDIT_APPL	((const char *)"proc_audit")
+#
+#define	PRIV_SYS_TRANS_LABEL	((const char *)"sys_trans_label")
+#define	PRIV_WIN_COLORMAP	((const char *)"win_colormap")
+#define	PRIV_WIN_CONFIG		((const char *)"win_config")
+#define	PRIV_WIN_DAC_READ	((const char *)"win_dac_read")
+#define	PRIV_WIN_DAC_WRITE	((const char *)"win_dac_write")
+#define	PRIV_WIN_DGA		((const char *)"win_dga")
+#define	PRIV_WIN_DEVICES	((const char *)"win_devices")
+#define	PRIV_WIN_DOWNGRADE_SL	((const char *)"win_downgrade_sl")
+#define	PRIV_WIN_FONTPATH	((const char *)"win_fontpath")
+#define	PRIV_WIN_MAC_READ	((const char *)"win_mac_read")
+#define	PRIV_WIN_MAC_WRITE	((const char *)"win_mac_write")
+#define	PRIV_WIN_SELECTION	((const char *)"win_selection")
+#define	PRIV_WIN_UPGRADE_SL	((const char *)"win_upgrade_sl")
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_TSOL_PRIV_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/tndb.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,405 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * from "tndb.h	7.34	01/08/31 SMI; TSOL 2.x"
+ */
+
+#ifndef	_SYS_TSOL_TNDB_H
+#define	_SYS_TSOL_TNDB_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
+#include <net/if.h>
+
+#ifdef _KERNEL
+#include <net/route.h>
+#include <sys/zone.h>
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* same on ILP32 and LP64 */
+typedef union tnaddr {
+	struct sockaddr_in	ip_addr_v4;
+	struct sockaddr_in6	ip_addr_v6;
+} tnaddr_t;
+
+#define	ta_family	ip_addr_v4.sin_family
+#define	ta_addr_v4	ip_addr_v4.sin_addr
+#define	ta_addr_v6	ip_addr_v6.sin6_addr
+#define	ta_port_v4	ip_addr_v4.sin_port
+#define	ta_port_v6	ip_addr_v6.sin6_port
+
+#define	TNADDR_EQ(addr1, addr2) \
+	(((addr1)->ta_family == AF_INET && (addr2)->ta_family == AF_INET && \
+	(addr1)->ta_addr_v4.s_addr == (addr2)->ta_addr_v4.s_addr) || \
+	((addr1)->ta_family == AF_INET6 && (addr2)->ta_family == AF_INET6 && \
+	IN6_ARE_ADDR_EQUAL(&(addr1)->ta_addr_v6, &(addr2)->ta_addr_v6)))
+
+/*
+ * structure for TN database access routines and TN system calls
+ */
+
+typedef enum tsol_dbops {
+	TNDB_NOOP = 0,
+	TNDB_LOAD = 1,
+	TNDB_DELETE = 2,
+	TNDB_FLUSH = 3,
+	TNDB_GET = 5
+} tsol_dbops_t;
+
+#define	TNTNAMSIZ 	32	/* template name size */
+#define	IP_STR_SIZE 	200	/* string ip address size */
+
+#define	TNRHDB_NCOL	2	/* # of columns in tnrhdb */
+
+/*
+ * For tnrhdb access library routines and tnrh(2TSOL)
+ * same for both ILP32 and LP64.
+ */
+typedef struct tsol_rhent {
+	short rh_prefix;		/* length of subnet mask */
+	short rh_unused;		/* padding */
+	tnaddr_t rh_address;		/* IP address */
+	char rh_template[TNTNAMSIZ];	/* template name */
+} tsol_rhent_t;
+
+typedef struct tsol_rhstr_s {
+	int	family;
+	char	*address;
+	char	*template;
+} tsol_rhstr_t;
+
+/*
+ * host types recognized by tsol hosts
+ */
+typedef enum {
+	UNLABELED	= 1,
+	SUN_CIPSO	= 3
+} tsol_host_type_t;
+
+typedef enum {
+	OPT_NONE	= 0,
+	OPT_CIPSO	= 1
+} tsol_ip_label_t;
+
+typedef struct cipso_tag_type_1 {
+	uchar_t	tag_type;		/* Tag Type (1) */
+	uchar_t	tag_length;		/* Length of Tag */
+	uchar_t	tag_align;		/* Alignment Octet */
+	uchar_t	tag_sl;			/* Sensitivity Level */
+	uchar_t	tag_cat[1];		/* Categories */
+} cipso_tag_type_1_t;
+
+#define	TSOL_CIPSO_MIN_LENGTH 6
+#define	TSOL_CIPSO_MAX_LENGTH IP_MAX_OPT_LENGTH
+#define	TSOL_TT1_MIN_LENGTH 4
+#define	TSOL_TT1_MAX_LENGTH 34
+
+#define	TSOL_CIPSO_DOI_OFFSET 2
+#define	TSOL_CIPSO_TAG_OFFSET 6
+
+typedef struct cipso_option {
+	uchar_t	cipso_type;		/* Type of option (134) */
+	uchar_t	cipso_length;		/* Length of option */
+	uchar_t	cipso_doi[4];		/* Domain of Interpretation */
+	uchar_t	cipso_tag_type[1];	/* variable length */
+} cipso_option_t;
+
+/*
+ * RIPSO classifications
+ */
+#define	TSOL_CL_TOP_SECRET 0x3d
+#define	TSOL_CL_SECRET 0x5a
+#define	TSOL_CL_CONFIDENTIAL 0x96
+#define	TSOL_CL_UNCLASSIFIED 0xab
+
+/*
+ * RIPSO protection authorities
+ */
+#define	TSOL_PA_GENSER 0x80
+#define	TSOL_PA_SIOP_ESI 0x40
+#define	TSOL_PA_SCI 0x20
+#define	TSOL_PA_NSA 0x10
+#define	TSOL_PA_DOE 0x08
+
+/*
+ * this mask is only used for tndb structures, and is different
+ * from t6mask_t bits definitions
+ */
+
+typedef unsigned int tnmask_t;
+
+/*
+ * unlabeled host structure for the tnrhtp template.
+ * same for both ILP32 and LP64.
+ */
+struct tsol_unl {
+	tnmask_t mask; /* tells which attributes are returned by the library */
+	bslabel_t def_label;	/* default label */
+	brange_t gw_sl_range;	/* for routing only */
+	blset_t sl_set;		/* label set */
+};
+
+/*
+ * CIPSO host structure for the tnrhtp template
+ * same for both ILP32 and LP64.
+ */
+struct tsol_cipso {
+	tnmask_t mask; /* tells which attributes are returned by the library */
+	bclear_t def_cl;	/* default clearance */
+	brange_t sl_range;	/* min/max SL range */
+	blset_t sl_set;		/* label set */
+};
+
+/*
+ * Valid keys and values of the key=value pairs for tnrhtp
+ */
+#define	TP_UNLABELED	"unlabeled"
+#define	TP_CIPSO	"cipso"
+#define	TP_ZONE		"zone"
+#define	TP_HOSTTYPE	"host_type"
+#define	TP_DOI		"doi"
+#define	TP_DEFLABEL	"def_label"
+#define	TP_MINLABEL	"min_sl"
+#define	TP_MAXLABEL	"max_sl"
+#define	TP_SET		"sl_set"
+
+#define	TP_COMMA	","
+
+#define	TNRHTP_NCOL	2	/* # of columns in tnrhtp */
+
+/*
+ * For tnrhtp access library routines and tnrhtp(2TSOL)
+ * same for both ILP32 and LP64.
+ */
+typedef struct tsol_tpent {
+	char name[TNTNAMSIZ]; /* template name */
+	tsol_host_type_t host_type; /* specifies host type */
+	int tp_doi;		/* Domain of Interpretation */
+#define	tp_cipso_doi_unl	tp_doi
+#define	tp_cipso_doi_cipso	tp_doi
+	union {
+		struct tsol_unl unl; /* template for unlabeled */
+#define	tp_mask_unl		un.unl.mask
+#define	tp_def_label		un.unl.def_label
+#define	tp_gw_sl_range		un.unl.gw_sl_range
+#define	tp_gw_sl_set		un.unl.sl_set
+
+		struct tsol_cipso cipso; /* template for CIPSO */
+#define	tp_mask_cipso		un.cipso.mask
+#define	tp_def_cl_cipso		un.cipso.def_cl
+#define	tp_sl_range_cipso	un.cipso.sl_range
+#define	tp_sl_set_cipso		un.cipso.sl_set
+	} un;
+} tsol_tpent_t;
+
+typedef struct tsol_tpstr_s {
+	char	*template;
+	char	*attrs;
+} tsol_tpstr_t;
+
+/*
+ * For tnmlp(2TSOL); same for both ILP32 and LP64.
+ */
+typedef struct tsol_mlpent {
+	zoneid_t	tsme_zoneid;
+	uint_t		tsme_flags;	/* TSOL_MEF_* */
+	tsol_mlp_t	tsme_mlp;
+} tsol_mlpent_t;
+
+#define	TSOL_MEF_SHARED	0x00000001	/* MLP defined on shared addresses */
+
+/*
+ * For tnzonecfg access library routines.
+ * List of MLPs ends with null entry, where protocol and port are both zero.
+ */
+typedef struct tsol_zcent {
+	char		zc_name[TNTNAMSIZ];
+	int		zc_doi;
+	bslabel_t	zc_label;
+	int		zc_match;
+	tsol_mlp_t	*zc_private_mlp;
+	tsol_mlp_t	*zc_shared_mlp;
+} tsol_zcent_t;
+#define	TSOL_MLP_END(mlp)	((mlp)->mlp_ipp == 0 && (mlp)->mlp_port == 0)
+
+typedef struct tsol_tpc {
+	kmutex_t		tpc_lock;	/* lock for structure */
+	uint_t			tpc_refcnt;	/* reference count */
+	boolean_t		tpc_invalid;	/* entry has been deleted */
+	struct tsol_tpent	tpc_tp;		/* template */
+} tsol_tpc_t;
+
+typedef struct tsol_tnrhc {
+	struct tsol_tnrhc 	*rhc_next;	/* link to next entry */
+	kmutex_t		rhc_lock;	/* lock for structure */
+	tnaddr_t		rhc_host;	/* IPv4/IPv6 host address */
+	tsol_tpc_t		*rhc_tpc;	/* pointer to template */
+	uint_t			rhc_refcnt;	/* Number of references */
+	char			rhc_invalid;	/* out-of-date rhc */
+	char			rhc_isbcast;	/* broadcast address */
+	char			rhc_local;	/* loopback or local interace */
+} tsol_tnrhc_t;
+
+/* Size of remote host hash tables in kernel */
+#define	TNRHC_SIZE 256
+#define	TSOL_MASK_TABLE_SIZE	33
+#define	TSOL_MASK_TABLE_SIZE_V6	129
+
+#ifdef	_KERNEL
+#define	TNRHC_HOLD(a)	{					\
+	mutex_enter(&(a)->rhc_lock);				\
+	(a)->rhc_refcnt++;					\
+	ASSERT((a)->rhc_refcnt > 0);				\
+	mutex_exit(&(a)->rhc_lock);				\
+}
+#define	TNRHC_RELE(a)	{					\
+	mutex_enter(&(a)->rhc_lock);				\
+	ASSERT((a)->rhc_refcnt > 0);				\
+	if (--(a)->rhc_refcnt <= 0)				\
+		tnrhc_free(a);					\
+	else							\
+		mutex_exit(&(a)->rhc_lock);			\
+}
+extern void tnrhc_free(tsol_tnrhc_t *);
+#define	TPC_HOLD(a)	{					\
+	mutex_enter(&(a)->tpc_lock);				\
+	(a)->tpc_refcnt++;					\
+	ASSERT((a)->tpc_refcnt > 0);				\
+	mutex_exit(&(a)->tpc_lock);				\
+}
+#define	TPC_RELE(a)	{					\
+	mutex_enter(&(a)->tpc_lock);				\
+	ASSERT((a)->tpc_refcnt > 0);				\
+	if (--(a)->tpc_refcnt <= 0)				\
+		tpc_free(a);					\
+	else							\
+		mutex_exit(&(a)->tpc_lock);			\
+}
+extern void tpc_free(tsol_tpc_t *);
+#endif	/* _KERNEL */
+
+/*
+ * The next three hashing macros are copied from macros in ip_ire.h.
+ */
+#define	TSOL_ADDR_HASH(addr, table_size)				\
+	(((((addr) >> 16) ^ (addr)) ^ ((((addr) >> 16) ^ (addr))>> 8))	\
+	% (table_size))
+
+#define	TSOL_ADDR_HASH_V6(addr, table_size)				\
+	(((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^			\
+	(addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^			\
+	(addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % (table_size))
+
+/* This assumes that table_size is a power of 2. */
+#define	TSOL_ADDR_MASK_HASH_V6(addr, mask, table_size)                   \
+	((((addr).s6_addr8[8] & (mask).s6_addr8[8]) ^                   \
+	((addr).s6_addr8[9] & (mask).s6_addr8[9]) ^                     \
+	((addr).s6_addr8[10] & (mask).s6_addr8[10]) ^                   \
+	((addr).s6_addr8[13] & (mask).s6_addr8[13]) ^                   \
+	((addr).s6_addr8[14] & (mask).s6_addr8[14]) ^                   \
+	((addr).s6_addr8[15] & (mask).s6_addr8[15])) & ((table_size) - 1))
+
+
+/*
+ * Constants used for getting the mask value in struct tsol_tpent
+ */
+enum {
+	TNT_DEF_LABEL,
+	TNT_DEF_CL,
+	TNT_SL_RANGE_TSOL, /* use this for both unl and zone */
+	TNT_CIPSO_DOI
+};
+
+/*
+ * mask definitions
+ */
+#define	tsol_tntmask(value) ((unsigned int)(1<<(value)))
+
+#define	TSOL_MSK_DEF_LABEL tsol_tntmask(TNT_DEF_LABEL)
+#define	TSOL_MSK_DEF_CL tsol_tntmask(TNT_DEF_CL)
+#define	TSOL_MSK_SL_RANGE_TSOL tsol_tntmask(TNT_SL_RANGE_TSOL)
+#define	TSOL_MSK_CIPSO_DOI tsol_tntmask(TNT_CIPSO_DOI)
+
+/*
+ * TN errors
+ */
+#define	TSOL_PARSE_ERANGE 1 /* result buffer not allocated */
+#define	TSOL_NOT_SUPPORTED 2 /* address family not supported */
+#define	TSOL_NOT_FOUND 3 /* search by * routines target not found */
+
+/*
+ * Structure used to hold a list of IP addresses.
+ */
+typedef struct tsol_address {
+	struct tsol_address	*next;
+	in_addr_t		ip_address;
+} tsol_address_t;
+
+/* This is shared between tcache and mdb */
+typedef struct tnrhc_hash_s {
+	tsol_tnrhc_t *tnrh_list;
+	kmutex_t tnrh_lock;
+} tnrhc_hash_t;
+
+#ifdef _KERNEL
+typedef enum {
+	mlptSingle,
+	mlptPrivate,
+	mlptShared,
+	mlptBoth
+} mlp_type_t;
+
+extern tsol_tpc_t *find_tpc(const void *, uchar_t, boolean_t);
+extern void tcache_init(void);
+extern in_port_t tsol_next_port(zone_t *, in_port_t, int, boolean_t);
+extern mlp_type_t tsol_mlp_port_type(zone_t *, uchar_t, uint16_t, mlp_type_t);
+extern zoneid_t tsol_mlp_findzone(uchar_t, uint16_t);
+extern int tsol_mlp_anon(zone_t *, mlp_type_t, uchar_t, uint16_t, boolean_t);
+extern void tsol_print_label(const blevel_t *, const char *);
+
+struct tsol_gc_s;
+struct tsol_gcgrp_s;
+struct tsol_gcgrp_addr_s;
+
+extern struct tsol_gc_s *gc_create(struct rtsa_s *, struct tsol_gcgrp_s *,
+    boolean_t *);
+extern void gc_inactive(struct tsol_gc_s *);
+extern int rtsa_validate(const struct rtsa_s *);
+extern struct tsol_gcgrp_s *gcgrp_lookup(struct tsol_gcgrp_addr_s *, boolean_t);
+extern void gcgrp_inactive(struct tsol_gcgrp_s *);
+extern int tnrh_load(const tsol_rhent_t *);
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_TSOL_TNDB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/tnet.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,95 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * from "tnet.h	7.44	02/10/09 SMI; TSOL 2.x"
+ */
+
+#ifndef	_SYS_TSOL_TNET_H
+#define	_SYS_TSOL_TNET_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tndb.h>
+#include <netinet/in.h>
+#include <inet/ip.h>
+#include <net/route.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+/* Maximum label returned by tsol_compute_label_v6 */
+#define	TSOL_MAX_IPV6_OPTION	(8 + IP_MAX_OPT_LENGTH)
+
+extern int tsol_tnrh_chk(tsol_tpent_t *, bslabel_t *, int);
+extern tsol_tnrhc_t *find_rhc_v4(const in_addr_t *);
+extern tsol_tnrhc_t *find_rhc_v6(const in6_addr_t *);
+extern int tsol_compute_label(const cred_t *, ipaddr_t, uchar_t *, boolean_t);
+extern int tsol_compute_label_v6(const cred_t *, const in6_addr_t *, uchar_t *,
+    boolean_t);
+extern int tsol_check_label(const cred_t *, mblk_t **, int *, boolean_t);
+extern int tsol_check_label_v6(const cred_t *, mblk_t **, int *, boolean_t);
+extern int tsol_prepend_option(uchar_t *, ipha_t *, int);
+extern int tsol_prepend_option_v6(uchar_t *, ip6_t *, int);
+extern int tsol_remove_secopt(ipha_t *, int);
+extern int tsol_remove_secopt_v6(ip6_t *, int);
+extern int tsol_update_sticky(ip6_pkt_t *, uint_t *, const uchar_t *);
+extern int tsol_update_options(uchar_t **, uint_t *, uint_t *,
+    const uchar_t *);
+extern boolean_t tsol_option_set(uchar_t **, uint_t *, uint_t, const uchar_t *,
+    uint_t);
+
+extern tsol_ire_gw_secattr_t *ire_gw_secattr_alloc(int);
+extern void ire_gw_secattr_free(tsol_ire_gw_secattr_t *);
+
+extern boolean_t tsol_can_reply_error(const mblk_t *);
+extern boolean_t tsol_receive_local(const mblk_t *, const void *, uchar_t,
+    boolean_t, const conn_t *);
+extern boolean_t tsol_can_accept_raw(mblk_t *, boolean_t);
+extern boolean_t tsol_get_pkt_label(mblk_t *, int);
+extern zoneid_t tsol_packet_to_zoneid(const mblk_t *);
+
+extern tsol_ip_label_t tsol_get_option(mblk_t *, uint8_t **);
+extern uchar_t *tsol_find_secopt_v6(const uchar_t *, uint_t, uchar_t **,
+    boolean_t *);
+
+extern int tsol_ire_match_gwattr(ire_t *, const ts_label_t *);
+extern int tsol_rtsa_init(rt_msghdr_t *, tsol_rtsecattr_t *, caddr_t);
+extern int tsol_ire_init_gwattr(ire_t *, uchar_t, tsol_gc_t *, tsol_gcgrp_t *);
+extern mblk_t *tsol_ip_forward(ire_t *, mblk_t *);
+
+extern mlp_type_t tsol_mlp_addr_type(zoneid_t, uchar_t, const void *);
+extern boolean_t tsol_check_interface_address(const ipif_t *);
+
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_TSOL_TNET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/tsol/tsyscall.h	Fri Mar 24 12:29:20 2006 -0800
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_TSOL_TSYSCALL_H
+#define	_SYS_TSOL_TSYSCALL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * the defines for subcode of labelsys system call.
+ */
+
+#define	TSOL_SYSLABELING	1
+#define	TSOL_TNRH		2
+#define	TSOL_TNRHTP		3
+#define	TSOL_TNMLP		4
+#define	TSOL_GETLABEL		5
+#define	TSOL_FGETLABEL		6
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_TSOL_TSYSCALL_H */
--- a/usr/src/uts/common/sys/ucred.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/ucred.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * File with private definitions for the ucred structure for use by the
@@ -36,6 +35,8 @@
 #include <sys/procfs.h>
 #include <sys/cred.h>
 #include <sys/priv.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/label_macro.h>
 
 #ifdef _KERNEL
 #include <c2/audit.h>
@@ -67,6 +68,7 @@
 	uint32_t	uc_audoff;	/* Audit info offset: 0 - no aud */
 	zoneid_t	uc_zoneid;	/* Zone id */
 	projid_t	uc_projid;	/* Project id */
+	uint32_t	uc_labeloff;	/* label offset: 0 - no label */
 					/* The rest goes here */
 };
 
@@ -82,6 +84,10 @@
 #define	UCAUD(uc)	(auditinfo64_addr_t *)(((uc)->uc_audoff == 0) ? NULL : \
 				((char *)(uc)) + (uc)->uc_audoff)
 
+/* Get peer security label info */
+#define	UCLABEL(uc)	(bslabel_t *)(((uc)->uc_labeloff == 0) ? NULL : \
+				((char *)(uc)) + (uc)->uc_labeloff)
+
 #define	UCRED_CRED_OFF	(sizeof (struct ucred_s))
 
 #endif /* _KERNEL || _STRUCTURED_PROC != 0 */
@@ -99,12 +105,14 @@
 #define	UCRED_PRIV_OFF	(UCRED_CRED_OFF + sizeof (prcred_t) + \
 			    (ngroups_max - 1) * sizeof (gid_t))
 #define	UCRED_AUD_OFF	(UCRED_PRIV_OFF + priv_prgetprivsize(NULL))
-#define	UCRED_SIZE	(UCRED_AUD_OFF + get_audit_ucrsize())
+#define	UCRED_LABEL_OFF	(UCRED_AUD_OFF + get_audit_ucrsize())
+#define	UCRED_SIZE	(UCRED_LABEL_OFF + sizeof (bslabel_t))
 
 struct proc;
 
 extern struct ucred_s *pgetucred(struct proc *);
-extern struct ucred_s *cred2ucred(const cred_t *, pid_t, void *);
+extern struct ucred_s *cred2ucred(const cred_t *, pid_t, void *,
+    const cred_t *);
 extern int get_audit_ucrsize(void);
 
 #else
@@ -117,7 +125,8 @@
 			sizeof (priv_chunk_t) * \
 			((ip)->priv_setsize * (ip)->priv_nsets - 1) + \
 			(ip)->priv_infosize + \
-			sizeof (auditinfo64_addr_t))
+			sizeof (auditinfo64_addr_t) + \
+			sizeof (bslabel_t))
 #endif
 
 extern struct ucred_s *_ucred_alloc(void);
--- a/usr/src/uts/common/sys/zone.h	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/sys/zone.h	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,6 +33,7 @@
 #include <sys/param.h>
 #include <sys/rctl.h>
 #include <sys/pset.h>
+#include <sys/tsol/label.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -57,6 +57,11 @@
 #define	GLOBAL_ZONEID	0
 #define	ZONEID_WIDTH	4	/* for printf */
 
+/*
+ * Special zoneid_t token to refer to all zones.
+ */
+#define	ALL_ZONES	(-1)
+
 /* system call subcodes */
 #define	ZONE_CREATE	0
 #define	ZONE_DESTROY	1
@@ -76,6 +81,7 @@
 #define	ZONE_ATTR_UNIQID	5
 #define	ZONE_ATTR_POOLID	6
 #define	ZONE_ATTR_INITPID	7
+#define	ZONE_ATTR_SLBL		8
 
 #define	ZONE_EVENT_CHANNEL	"com.sun:zones:status"
 #define	ZONE_EVENT_STATUS_CLASS	"status"
@@ -103,6 +109,9 @@
 	caddr32_t extended_error;
 	caddr32_t zfsbuf;
 	size32_t  zfsbufsz;
+	int match;
+	int doi;
+	caddr32_t label;
 } zone_def32;
 #endif
 typedef struct {
@@ -115,6 +124,9 @@
 	int *extended_error;
 	const char *zfsbuf;
 	size_t zfsbufsz;
+	int match;			/* match level */
+	int doi;			/* DOI for label */
+	const bslabel_t *label;		/* label associated with zone */
 } zone_def;
 
 /* extended error information */
@@ -192,7 +204,6 @@
  */
 #define	ZONE_DOOR_PATH		ZONES_TMPDIR "/%s.zoneadmd_door"
 
-
 #ifdef _KERNEL
 /*
  * We need to protect the definition of 'list_t' from userland applications and
@@ -293,6 +304,10 @@
 	 * List of ZFS datasets exported to this zone.
 	 */
 	list_t		zone_datasets;	/* list of datasets */
+
+	ts_label_t	*zone_slabel;
+	int		zone_match;
+	tsol_mlp_list_t zone_mlps;	/* MLPs on zone-private addresses */
 } zone_t;
 
 /*
@@ -317,8 +332,10 @@
 extern void zone_task_hold(zone_t *);
 extern void zone_task_rele(zone_t *);
 extern zone_t *zone_find_by_id(zoneid_t);
+extern zone_t *zone_find_by_label(const ts_label_t *);
 extern zone_t *zone_find_by_name(char *);
 extern zone_t *zone_find_by_path(const char *);
+extern zone_t *zone_find_by_any_path(const char *, boolean_t);
 extern zoneid_t getzoneid(void);
 
 /*
@@ -401,11 +418,6 @@
 #define	ZONE_SPECIALPID(x)	 ((x) == 0 || (x) == 1)
 
 /*
- * Special zoneid_t token to refer to all zones.
- */
-#define	ALL_ZONES	(-1)
-
-/*
  * Zone-safe version of thread_create() to be used when the caller wants to
  * create a kernel thread to run within the current zone's context.
  */
--- a/usr/src/uts/common/syscall/ppriv.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/syscall/ppriv.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,7 +32,6 @@
 #include <sys/cred_impl.h>
 #include <sys/errno.h>
 #include <sys/proc.h>
-#include <sys/debug.h>
 #include <sys/priv_impl.h>
 #include <sys/policy.h>
 #include <sys/ddi.h>
@@ -210,22 +208,27 @@
 }
 
 /*
- * Set privilege flags
+ * Set process flags in the given target cred.  If NULL is specified, then
+ * CRED() is used; otherwise the cred is assumed to be modifiable (i.e. newly
+ * crdup'ed, or equivalent).  Some flags are set in the proc rather than cred;
+ * for these, curproc is always used.
  *
  * For now we cheat: the flags are actually bit masks so we can simplify
  * some; we do make sure that the arguments are valid, though.
  */
 
-static int
-setpflags(uint_t flag, uint_t val)
+int
+setpflags(uint_t flag, uint_t val, cred_t *tcr)
 {
 	cred_t *cr, *pcr;
 	proc_t *p = curproc;
 	uint_t newflags;
+	boolean_t use_curcred = (tcr == NULL);
 
 	if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
+	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT &&
 	    flag != __PROC_PROTECT)) {
-		return (set_errno(EINVAL));
+		return (EINVAL);
 	}
 
 	if (flag == __PROC_PROTECT) {
@@ -238,11 +241,13 @@
 		return (0);
 	}
 
-	cr = cralloc();
-
-	mutex_enter(&p->p_crlock);
-
-	pcr = p->p_cred;
+	if (use_curcred) {
+		cr = cralloc();
+		mutex_enter(&p->p_crlock);
+		pcr = p->p_cred;
+	} else {
+		cr = pcr = tcr;
+	}
 
 	newflags = CR_FLAGS(pcr);
 
@@ -253,20 +258,38 @@
 
 	/* No change */
 	if (CR_FLAGS(pcr) == newflags) {
-		mutex_exit(&p->p_crlock);
-		crfree(cr);
+		if (use_curcred) {
+			mutex_exit(&p->p_crlock);
+			crfree(cr);
+		}
 		return (0);
 	}
 
+	/*
+	 * Need net_mac_aware priv to turn either net_mac_aware* flag on
+	 * current cred.
+	 */
+	if ((flag == NET_MAC_AWARE || flag == NET_MAC_AWARE_INHERIT) &&
+	    (val == 1) && use_curcred) {
+		if (secpolicy_net_mac_aware(cr) != 0) {
+			mutex_exit(&p->p_crlock);
+			crfree(cr);
+			return (EPERM);
+		}
+	}
+
 	/* Trying to unset PA; if we can't, return an error */
 	if (flag == PRIV_AWARE && val == 0 && !priv_can_clear_PA(pcr)) {
-		mutex_exit(&p->p_crlock);
-		crfree(cr);
-		return (set_errno(EPERM));
+		if (use_curcred) {
+			mutex_exit(&p->p_crlock);
+			crfree(cr);
+		}
+		return (EPERM);
 	}
 
 	/* Committed to changing the flag */
-	crcopy_to(pcr, cr);
+	if (use_curcred)
+		crcopy_to(pcr, cr);
 	if (flag == PRIV_AWARE) {
 		if (val != 0)
 			priv_set_PA(cr);
@@ -276,11 +299,11 @@
 		CR_FLAGS(cr) = newflags;
 	}
 
-	p->p_cred = cr;
-
-	mutex_exit(&p->p_crlock);
-
-	crset(p, cr);
+	if (use_curcred) {
+		p->p_cred = cr;
+		mutex_exit(&p->p_crlock);
+		crset(p, cr);
+	}
 
 	return (0);
 }
@@ -288,13 +311,14 @@
 /*
  * Getpflags.  Currently only implements single bit flags.
  */
-static uint_t
-getpflags(uint_t flag)
+uint_t
+getpflags(uint_t flag, const cred_t *cr)
 {
-	if (flag != PRIV_DEBUG && flag != PRIV_AWARE)
-		return (set_errno(EINVAL));
+	if (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
+	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT)
+		return ((uint_t)-1);
 
-	return ((CR_FLAGS(CRED()) & flag) != 0);
+	return ((CR_FLAGS(cr) & flag) != 0);
 }
 
 /*
@@ -303,6 +327,8 @@
 int
 privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize)
 {
+	int retv;
+
 	switch (code) {
 	case PRIVSYS_SETPPRIV:
 		if (bufsize < sizeof (priv_set_t))
@@ -315,10 +341,11 @@
 	case PRIVSYS_GETIMPLINFO:
 		return (getprivimplinfo(buf, bufsize));
 	case PRIVSYS_SETPFLAGS:
-		return (setpflags((uint_t)op, (uint_t)type));
+		retv = setpflags((uint_t)op, (uint_t)type, NULL);
+		return (retv != 0 ? set_errno(retv) : 0);
 	case PRIVSYS_GETPFLAGS:
-		return ((int)getpflags((uint_t)op));
-
+		retv = (int)getpflags((uint_t)op, CRED());
+		return (retv == -1 ? set_errno(EINVAL) : retv);
 	}
 	return (set_errno(EINVAL));
 }
--- a/usr/src/uts/common/syscall/sendfile.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/syscall/sendfile.c	Fri Mar 24 12:29:20 2006 -0800
@@ -54,6 +54,11 @@
 
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+/* swilly code in sys/socketvar.h turns off DEBUG */
+#ifdef __lint
+#define	DEBUG
+#endif
+
 #include <netinet/in.h>
 #include <sys/sendfile.h>
 #include <sys/un.h>
--- a/usr/src/uts/common/syscall/ucredsys.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/common/syscall/ucredsys.c	Fri Mar 24 12:29:20 2006 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -111,7 +110,7 @@
 	if (kpc.pc_cr != NULL) {
 		ASSERT(err == 0);
 
-		uc = cred2ucred(kpc.pc_cr, kpc.pc_cpid, NULL);
+		uc = cred2ucred(kpc.pc_cr, kpc.pc_cpid, NULL, CRED());
 
 		crfree(kpc.pc_cr);
 
@@ -172,7 +171,7 @@
 			return (set_errno(err));
 	}
 
-	uc = cred2ucred(pcr, pid, NULL);
+	uc = cred2ucred(pcr, pid, NULL, CRED());
 
 	crfree(pcr);
 
--- a/usr/src/uts/i86pc/os/startup.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/i86pc/os/startup.c	Fri Mar 24 12:29:20 2006 -0800
@@ -49,18 +49,14 @@
 #include <sys/kstat.h>
 
 #include <sys/reboot.h>
-#include <sys/uadmin.h>
 
 #include <sys/cred.h>
 #include <sys/vnode.h>
 #include <sys/file.h>
 
 #include <sys/procfs.h>
-#include <sys/acct.h>
 
 #include <sys/vfs.h>
-#include <sys/dnlc.h>
-#include <sys/var.h>
 #include <sys/cmn_err.h>
 #include <sys/utsname.h>
 #include <sys/debug.h>
@@ -70,12 +66,8 @@
 #include <sys/bootconf.h>
 #include <sys/varargs.h>
 #include <sys/promif.h>
-#include <sys/prom_emul.h>	/* for create_prom_prop */
 #include <sys/modctl.h>		/* for "procfs" hack */
 
-#include <sys/consdev.h>
-#include <sys/frame.h>
-
 #include <sys/sunddi.h>
 #include <sys/sunndi.h>
 #include <sys/ndi_impldefs.h>
@@ -84,11 +76,9 @@
 #include <sys/regset.h>
 #include <sys/clock.h>
 #include <sys/pte.h>
-#include <sys/mmu.h>
 #include <sys/tss.h>
 #include <sys/stack.h>
 #include <sys/trap.h>
-#include <sys/pic.h>
 #include <sys/fp.h>
 #include <vm/anon.h>
 #include <vm/as.h>
@@ -102,7 +92,6 @@
 #include <vm/seg_kp.h>
 #include <sys/memnode.h>
 #include <vm/vm_dep.h>
-#include <sys/swap.h>
 #include <sys/thread.h>
 #include <sys/sysconf.h>
 #include <sys/vm_machparam.h>
@@ -111,14 +100,12 @@
 #include <vm/hat.h>
 #include <vm/hat_i86.h>
 #include <sys/pmem.h>
-#include <sys/instance.h>
 #include <sys/smp_impldefs.h>
 #include <sys/x86_archext.h>
 #include <sys/segments.h>
 #include <sys/clconf.h>
 #include <sys/kobj.h>
 #include <sys/kobj_lex.h>
-#include <sys/prom_emul.h>
 #include <sys/cpc_impl.h>
 #include <sys/chip.h>
 #include <sys/x86_archext.h>
@@ -1365,6 +1352,8 @@
 	if (modload("fs", "devfs") == -1)
 		halt("Can't load devfs");
 
+	(void) modloadonly("sys", "lbl_edition");
+
 	dispinit();
 
 	/*
@@ -2411,7 +2400,7 @@
 int	enable_relaxed_mtrr = 0;
 
 void
-setup_mtrr()
+setup_mtrr(void)
 {
 	int i, ecx;
 	int vcnt;
@@ -2463,7 +2452,7 @@
  * On other cpu's its invoked from mp_startup().
  */
 void
-mtrr_sync()
+mtrr_sync(void)
 {
 	uint_t	crvalue, cr0_orig;
 	int	vcnt, i, ecx;
@@ -2512,7 +2501,7 @@
  * resync mtrr so that BIOS is happy. Called from mdboot
  */
 void
-mtrr_resync()
+mtrr_resync(void)
 {
 	if ((x86_feature & X86_PAT) && enable_relaxed_mtrr) {
 		/*
@@ -2525,7 +2514,7 @@
 }
 
 void
-get_system_configuration()
+get_system_configuration(void)
 {
 	char	prop[32];
 	u_longlong_t nodes_ll, cpus_pernode_ll, lvalue;
--- a/usr/src/uts/req.flg	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/req.flg	Fri Mar 24 12:29:20 2006 -0800
@@ -1,11 +1,11 @@
 #!/bin/sh
 #
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +20,6 @@
 #
 # CDDL HEADER END
 #
-#
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
@@ -52,3 +51,4 @@
 find_files "s.*" usr/src/common/acl
 find_files "s.*" usr/src/common/zfs
 find_files "s.*" usr/src/common/smbios
+find_files "s.*" usr/src/common/tsol
--- a/usr/src/uts/sun4/os/startup.c	Thu Mar 23 19:49:27 2006 -0800
+++ b/usr/src/uts/sun4/os/startup.c	Fri Mar 24 12:29:20 2006 -0800
@@ -1638,6 +1638,8 @@
 	if (modloadonly("misc", "swapgeneric") == -1)
 		halt("Can't load swapgeneric");
 
+	(void) modloadonly("sys", "lbl_edition");
+
 	dispinit();
 
 	/*