diff options
Diffstat (limited to 'usr/src')
408 files changed, 38783 insertions, 6690 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 96414c9e3c..39dcec77c2 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -350,6 +350,8 @@ COMMON_SUBDIRS = \ lib/libsmbios \ lib/libsmedia \ lib/libthread \ + lib/libtsnet \ + lib/libtsol \ lib/libumem \ lib/libuutil \ lib/libwanboot \ diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index b55eb30c94..27473441b8 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -200,6 +200,7 @@ ROOT.BIN= \ /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.1:= REALPATH=../../lib/libthread.so.1 $(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.ln:= REALPATH=../../lib/llib-lthread.ln $(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 @@ $(ROOT)/usr/lib/$(MACH64)/libthread_db.so.1:= \ 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 @@ $(ROOT)/usr/lib/$(MACH64)/llib-lthread.ln:= \ 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 @@ SYM.USRLIB= \ /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 @@ SYM.USRLIB= \ /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 @@ SYM.USRLIB= \ /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 @@ SYM.USRLIB64= \ /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 @@ SYM.USRLIB64= \ /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 \ diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index b72d2d2104..645eb783ad 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -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 @@ BSMSUBDIRS= \ auditd \ auditreduce \ auditstat \ - dminfo \ praudit \ bsmconv \ bsmrecord \ diff --git a/usr/src/cmd/allocate/Makefile b/usr/src/cmd/allocate/Makefile index 6b3055bce1..53cf843d11 100644 --- a/usr/src/cmd/allocate/Makefile +++ b/usr/src/cmd/allocate/Makefile @@ -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 @@ ROOTSECDEV = $(ROOTSEC)/dev 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) + +LINKPROGalloc = deallocate list_devices +LINKPROGmkdevalloc = mkdevmaps + -# make DFLAGS=-DDEBUG +POFILE = allocate_all.po +POFILES = $(OBJS:%.o=%.po) $(ALLSCRIPTS:%.sh=%.po) -DFLAGS= +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 -SRCS = $(OBJS:%.o=%.c) +OBJS = $(PROGallocOBJS) \ + $(PROGmkdevallocOBJS) \ + $(PROGdminfoOBJS) \ + $(PROGaudioOBJS) -FILEMODE= 0755 -DIRMODE= 0755 -OWNER= root -GROUP= sys +SRCS = $(OBJS:%.o=%.c) +$(ROOTUSRSBIN)/% := FILEMODE = 555 +$(ROOTUSRSBIN)/allocate := FILEMODE = 4555 $(ROOTUSRSBIN)/% := OWNER = root $(ROOTUSRSBIN)/% := GROUP = bin +$(ROOTSECDEV)/% := FILEMODE = 0400 +$(ROOTSECDEV)/% := OWNER = root +$(ROOTSECDEV)/% := GROUP = bin +$(ROOTSECLIB)/% := FILEMODE = 0555 +$(ROOTSECLIB)/% := OWNER = root +$(ROOTSECLIB)/% := GROUP = sys + +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 + +CLOBBERFILES += $(SCRIPTS) -$(ROOTUSRSBIN)/allocate := FILEMODE = 04755 -$(ROOTUSRSBIN)/deallocate := FILEMODE = 04755 -$(ROOTUSRSBIN)/list_devices := FILEMODE = 04755 +.KEEP_STATE: -$(ROOTSECDEV)/% := FILEMODE = 0400 -$(ROOTSECDEV)/% := OWNER = root -$(ROOTSECDEV)/% := GROUP = bin +all : $(PROG) $(RTLCKS) $(SCRIPTS) -$(ROOTSECLIB)/% := FILEMODE = 0751 +install : $(PROG) $(ROOTDIRS) $(ROOTPROG) $(ROOTLOCKS) \ + $(ROOTSCRIPTS) $(ROOTLINKS) -allocate := LDLIBS += -lbsm -lsec -lsecdb +$(RTLCKS): + $(TOUCH) $@ -.KEEP_STATE: +$(ROOTSECLIB)/%: %.sh + $(INS.rename) -all : $(PROG) $(RTLCKS) $(SCRIPTS) +$(PROGalloc) : $(PROGallocOBJS) + $(LINK.c) $(PROGallocOBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) -install : all $(ROOTDIRS) $(ROOTPROG) $(ROOTLOCKS) $(ROOTSCRIPTS) - $(RM) $(ROOTUSRSBIN)/$(DEFILE) - $(LN) $(ROOTUSRSBIN)/$(PROG1) $(ROOTUSRSBIN)/$(DEFILE) - $(RM) $(ROOTUSRSBIN)/$(LISTFILE) - $(LN) $(ROOTUSRSBIN)/$(PROG1) $(ROOTUSRSBIN)/$(LISTFILE) +$(PROGmkdevalloc) : $(PROGmkdevallocOBJS) + $(LINK.c) $(PROGmkdevallocOBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) -$(PROG) : $$(POBJS) - $(LINK.c) $(POBJS) -o $@ $(LDLIBS) +$(PROGdminfo) : $(PROGdminfoOBJS) + $(LINK.c) $(PROGdminfoOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) -$(RTLCKS): - $(TOUCH) $@ +$(PROGaudio) : $(PROGaudioOBJS) + $(LINK.c) $(PROGaudioOBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) -$(ROOTDIRS): +$(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 @@ $(ALLSCRIPTS): $(SCRIPTS:%=%.sh) $(CAT) $(SCRIPTS:%=%.sh) > $@ clean : - $(RM) $(OBJS) $(RTLCKS) $(ALLSCRIPTS) + $(RM) $(PROG) $(RTLCKS) $(OBJS) \ + $(SCRIPTS) $(ALLSCRIPTS) $(POFILE) $(POFILES) lint : lint_SRCS diff --git a/usr/src/cmd/allocate/allocate.c b/usr/src/cmd/allocate/allocate.c index a2c1c967f9..36f0050f2b 100644 --- a/usr/src/cmd/allocate/allocate.c +++ b/usr/src/cmd/allocate/allocate.c @@ -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]; - - 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", - use[0], use[1], use[2], use[3], use[4]); + if (system_labeled) { + char *use[9]; + + 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%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: - msg = gettext( - "No device allocate file entry for specified device."); + case CLEANERR: + msg = gettext("Unable to clean up device."); break; - case NODMAPENT: + case CNTDEXECERR: 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 NALLOCU: - msg = gettext("Specified device is allocated to another user."); + case DAUTHERR: + msg = gettext("Device not allocatable."); break; - case NOTAUTH: - msg = gettext("Not authorized for specified operation."); + case DEFATTRSERR: + msg = gettext("No default attributes for specified " + "device type."); break; - case CNTFRC: - msg = gettext("Can't force deallocate specified device."); + case DEVLKERR: + msg = gettext("Concurrent operations for specified device, " + "try later."); break; - case CNTDEXEC: - msg = gettext( - "Can't exec device-clean program for specified device."); + case DEVLONGERR: + msg = gettext("Device name is too long."); break; - case NO_DEVICE: - msg = gettext( - "Can't find a device of type requested to allocate."); + case DEVNALLOCERR: + msg = gettext("Device not allocated."); break; - case DSPMISS: - msg = gettext( - "Device special file(s) missing for specified device."); + case DEVNAMEERR: + msg = gettext("Device name error."); break; - case ALLOCERR: + case DEVSTATEERR: msg = gettext("Device specified is in allocate error state."); break; - case CHOWN_PERR: - msg = gettext("Process lacks privilege required to chown()."); + case DEVZONEERR: + msg = gettext("Can't find name of the zone to which " + "device is allocated."); break; - case ALLOC: - msg = gettext("Device already allocated."); + case DSPMISSERR: + msg = gettext( + "Device special file(s) missing for specified device."); break; - case ALLOC_OTHER: - msg = gettext("Device allocated to another user."); + case LABELRNGERR: + msg = gettext( + "Operation inconsistent with device's label range."); break; - case NALLOC: - msg = gettext("Device not allocated."); + case LOGINDEVPERMERR: + msg = gettext("Device controlled by logindevperm(4)"); break; - case AUTHERR: - msg = gettext("Device not allocatable."); + case NODAERR: + msg = gettext("No entry for specified device."); break; - case CLEAN_ERR: - msg = gettext("Unable to clean up the device."); + case NODMAPERR: + msg = gettext("No entry for specified device."); break; - case SETACL_PERR: - msg = gettext("Process lacks privilege required to set ACL."); + case PREALLOCERR: + msg = gettext("Device already allocated."); break; - case DEVNAME_ERR: - msg = gettext("Error forming device name."); + case SETACLERR: + msg = gettext("Failed to set ACL."); break; - case DEVNAME_TOOLONG: - msg = gettext("Device name is too long."); + case UAUTHERR: + msg = gettext( + "User lacks authorization required for this operation."); + break; + 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 @@ getenvent(char *name, char *env[]) 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 @@ main(int argc, char *argv[], char *envp[]) 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 'U': - optflg |= USERNAME; - uname = optarg; + case 'w': + if (system_labeled) { + optflg |= WINDOWING; + windowing = 1; + } else { + usage(func); + } break; - case 'g': - optflg |= TYPE; + 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 '?': default : usage(func); } } - if ((optflg & TYPE) && (optflg & FORCE)) - usage(func); - /* * allocate(1) must be supplied with one device argument */ @@ -282,11 +386,33 @@ main(int argc, char *argv[], char *envp[]) } 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 @@ main(int argc, char *argv[], char *envp[]) 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,23 +449,63 @@ main(int argc, char *argv[], char *envp[]) } 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 's': - optflg |= SILENT; + case 'a': + if (system_labeled) { + /* + * list auths, cleaning programs, + * labels. + */ + optflg |= LISTATTRS; + } else { + usage(func); + } break; - case 'U': - optflg |= USERID; - uid = atoi(optarg); + case 'd': + if (system_labeled) { + /* + * list devalloc_defaults + */ + optflg |= LISTDEFS; + } else { + usage(func); + } break; case 'l': - optflg |= LIST; + optflg |= LISTALL; break; case 'n': - optflg |= FREE; + optflg |= LISTFREE; + break; + case 's': + optflg |= SILENT; break; case 'u': - optflg |= CURRENT; + 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 '?': default : @@ -344,11 +513,22 @@ main(int argc, char *argv[], char *envp[]) } } - 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 @@ main(int argc, char *argv[], char *envp[]) } 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; + } 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; + 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 @@ main(int argc, char *argv[], char *envp[]) 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); + } +} diff --git a/usr/src/cmd/allocate/allocate.h b/usr/src/cmd/allocate/allocate.h index 29f222a29d..f6a7956f85 100644 --- a/usr/src/cmd/allocate/allocate.h +++ b/usr/src/cmd/allocate/allocate.h @@ -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 @@ extern "C" { #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 } diff --git a/usr/src/cmd/allocate/allocate3.c b/usr/src/cmd/allocate/allocate3.c index 1e24722cbb..7b4ef265f3 100644 --- a/usr/src/cmd/allocate/allocate3.c +++ b/usr/src/cmd/allocate/allocate3.c @@ -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) == ALLOC_MODE) + !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \ + DEV_ERRORED(sbuf) || DEV_INVALID(sbuf))) +#define ALLOC_CLEAN "-A" +#define DEALLOC_CLEAN "-D" +#define DAC_DIR "/etc/security/dev" #define DEVICE_AUTH_SEPARATOR "," -#define PROCFS "/proc/" +#define LOCALDEVICE "/dev/console" +#define PROCFS "/proc/" +#define SFF_NO_ERROR 0x1 + +#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 */ +/*ARGSUSED*/ +int +_is_local(uid_t uid) +{ + struct stat statbuf; -static int -is_authorized(char *auth_list, uid_t uid) + if (stat(LOCALDEVICE, &statbuf) == 0 && + statbuf.st_uid == uid) + return (1); + + return (0); +} + +/* + * Checks if the user with the specified uid has the specified authorization + */ +int +_is_authorized(char *auths, uid_t uid) { - char *auth; - struct passwd *pw; + char *dcp, *authlist, *lasts; + char pw_buf[NSS_BUFLEN_PASSWD]; + struct passwd pw_ent; - pw = getpwuid(uid); - if (pw == NULL) { - dprintf("Can't get user info for uid=%d\n", (int)uid); + /* + * 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); - 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); + return (dcp != NULL); } -static int -check_devs(char *list) +/* + * Checks if the specified user has authorization for the device + */ +int +_is_dev_authorized(devalloc_t *da, uid_t uid) { - char *file; + 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); +} - if (access(file, F_OK) == -1) { - dprintf("Unable to access file %s\n", file); - return (-1); +int +check_devs(devmap_t *dm) +{ + int status = 0; + char **file; + + 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 (0); + + return (status); } -static void -print_dev(devmap_t *dev_list) +int +print_da_defs(da_defs_t *da_defs) { - char *file; + char optbuf[BUFSIZ]; + char *p = NULL; - (void) printf(gettext("device: %s "), dev_list->dmap_devname); - (void) printf(gettext("type: %s "), dev_list->dmap_devtype); - (void) printf(gettext("files: ")); + 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); + } - file = strtok(dev_list->dmap_devlist, " "); - while (file != NULL) { - (void) printf("%s ", file); - file = strtok(NULL, " "); + return (0); +} + +void +print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm, + struct file_info *fip) +{ + char *p = NULL; + char optbuf[BUFSIZ]; + + (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"); } -static int -list_device(int optflg, uid_t uid, char *device) +void +print_dev(devmap_t *dm) { - 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); - } - - 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 (stat(file_name, &stat_buf)) { - dprintf("Unable to stat %s\n", file_name); - dperror("Error:"); - return (DACACC); + 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"); +} - if ((optflg & FREE) && DEV_ALLOCATED(stat_buf)) - return (ALLOC); - - 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); - - if ((list = strdup(dev_list->dmap_devlist)) == NULL) - return (SYSERROR); +/* ARGSUSED */ +int +_list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename) +{ + 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; - if (check_devs(list) == -1) { - free(list); - return (DSPMISS); + 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 (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 (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); - print_dev(dev_list); + error = 0; - 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; - - if (optflg & USERID) { - if (!is_authorized(DEVICE_REVOKE_AUTH, getuid())) - return (NOTAUTH); + int error = 0; + da_defs_t *da_defs; + devalloc_t *da; + + if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) { + /* + * Private interface for GUI. + */ + (void) lock_dev(NULL); + (void) puts(DA_DB_LOCK); + return (0); } - setdaent(); - - if (device) { - return (list_device(optflg, uid, device)); + if (optflag & USERID) { + /* + * we need device.revoke to list someone else's devices + */ + if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) + return (UAUTHERR); } - - if ((dev_dir = opendir(DAC_DIR)) == NULL) { - - dperror("Can't open DAC_DIR"); - return (DACACC); + 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); + } } - - 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; + setdaent(); + if (device) { + /* + * 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 @@ list_devices(int optflg, uid_t uid, char *device) * 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 = CHOWNERR; + } + } else do { if (chown(file, owner, group) == -1) { - dperror("newdac, unable to chown"); - err = CHOWN_PERR; + 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 @@ newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) 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) { - - dprintf("Allocating %s\n", file); - if ((err = newdac(file, uid, getgid(), ALLOC_MODE)) != 0) { - (void) newdac(file, ALLOC_UID, ALLOC_GID, + int i; + int error = 0; + char **file; + gid_t gid = getgid(); + mode_t mode = ALLOC_MODE; + + 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; } - - file = strtok(NULL, " "); } - return (0); + 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; + } + } + } + + return (error); } /* @@ -319,33 +672,32 @@ mk_alloc(char *list, uid_t uid) * 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 @@ mk_revoke(int optflg, char *file) 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 @@ mk_revoke(int optflg, char *file) (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); + 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); - - 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, " "); - } - exit(error); - default: - while (wait(&status) != child); - if (WIFEXITED(status)) { - return (WEXITSTATUS(status)); + int status; + char **file; + + 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; } - 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) { - char *mode, *cmd; - int status; - int c; + 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); + } - if ((optflg & (FORCE_ALL | SILENT)) == (FORCE_ALL | SILENT)) + return (status); +} + +int +exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename, + char *clean_arg) +{ + 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; + + 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; - - 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); + 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; + + 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; } - if (!(optflg & FORCE) && stat_buf.st_uid != uid && + audit_allocate_device(fname); + + 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)) { - return (NALLOCU); + error = ALLOCUERR; + goto out; } - - 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); + if (!DEV_ALLOCATED(stat_buf)) { + if (DEV_ERRORED(stat_buf)) { + if (!(optflag & FORCE)) { + error = DEVSTATEERR; + goto out; + } + } else { + error = DEVNALLOCERR; + goto out; + } } - /* 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); + 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 ((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 ((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 { - if (mk_unalloc(optflg, list) != 0) { - (void) newdac(file_name, ALLOC_UID, ALLOC_GID, - ALLOC_ERR_MODE); - free(list); - list = NULL; - EXIT(DEVLST); - } + error = 0; } } - if (list != NULL) - free(list); - if (exec_clean(optflg, dev_ent->da_devname, dev_ent->da_devexec)) - EXIT(CLEAN_ERR); +out: + if (dm_new) + freedmapent(dm_new); return (error); } -static int -allocate_dev(int optflg, uid_t uid, devalloc_t *dev_ent) +int +_allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename) { - 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); + 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; } - audit_allocate_device(file_name); + (void) audit_allocate_device(fname); - if (stat(file_name, &stat_buf)) { - dprintf("Unable to stat %s\n", file_name); + if (stat(fname, &stat_buf) != 0) { + dprintf("Unable to stat %s\n", fname); dperror("Error:"); - return (DACACC); + 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 (optflg & FORCE) { - if (optflg & SILENT) - deallocate_optflg = FORCE|SILENT; + if (optflag & FORCE) { + if (optflag & SILENT) + dealloc_optflag = FORCE|SILENT; else - deallocate_optflg = FORCE; - - if (deallocate_dev(deallocate_optflg, dev_ent, uid)) { + dealloc_optflag = FORCE; + if (_deallocate_dev(dealloc_optflag, da, dm, uid, + zonename)) { dprintf("Couldn't force deallocate device %s\n", - dev_ent->da_devname); - return (CNTFRC); + da->da_devname); + error = CNTFRCERR; + goto out; } } else if (stat_buf.st_uid == uid) { - return (ALLOC); - } else - return (ALLOC_OTHER); + error = PREALLOCERR; + goto out; + } else { + 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 ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) - return (ALLOCERR); - if (strcmp(dev_ent->da_devauth, "*") == 0) { - dprintf("Device %s is not allocatable\n", dev_ent->da_devname); - return (AUTHERR); + (void) audit_allocate_list(dm->dmap_devlist); + + if ((error = mk_alloc(dm, uid, &zpath)) != 0) { + (void) mk_unalloc(optflag, dm); + goto out; } - if (strcmp(dev_ent->da_devauth, "@")) { - if (!is_authorized(dev_ent->da_devauth, uid)) { - dprintf("User %d is unauthorized to allocate\n", - (int)uid); - return (IMPORT_ERR); + 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; } } - - 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); + error = 0; +out: + if (zpath.count) { + for (i = 0; i < zpath.count; i++) + free(zpath.path[i]); + free(zpath.path); } + freedmapent(dm); + return (error); +} - if ((list = strdup(dev_list->dmap_devlist)) == NULL) - return (SYSERROR); +void +_store_devnames(int *count, struct devnames *dnms, char *zonename, + devalloc_t *da, int flag) +{ + int i; - if (check_devs(list) == -1) { - free(list); - return (DSPMISS); + 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); } +} - /* All checks passed, time to lock and allocate */ - if ((error = lock_dev(file_name)) != 0) { - free(list); - return (error); +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); } - - 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); + 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); - /* refresh list from check_devs overwritting it */ - (void) strcpy(list, dev_list->dmap_devlist); - audit_allocate_list(list); + return (error); +} - 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); +/* 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); - free(list); - return (0); + return (error); } -int -allocate(int optflg, uid_t uid, char *device) +static int +_dev_file_name(struct state_file *sfp, devmap_t *dm) { - devalloc_t *dev_ent; - devmap_t *dev_list; + 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 (((optflg & FORCE) || uid != getuid()) && - !is_authorized(DEVICE_REVOKE_AUTH, getuid())) - return (NOTAUTH); + return (0); +} - setdaent(); - setdmapent(); +/* + * _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 (!(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); + if ((zlabel = getzonelabelbyname(zonename)) == NULL) { + dprintf("unable to get label for %s zone\n", zonename); + return (-1); + } + if (flag == CHECK_DRANGE) { + blrange_t drange; + + 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; + + (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); + 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); } - return (allocate_dev(optflg, uid, dev_ent)); } + free(zlabel); - 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); + return (0); +} + +int +create_znode(char *zonename, struct zone_path *zpath, devmap_t *list) +{ + int i; + int size; + int len = 0; + int fcount = 0; + char *p, *tmpfile, *zoneroot; + char **file; + char zonepath[MAXPATHLEN]; + struct stat statb; + + 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]; + + 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); } + 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'; } - 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; - - if (optflg & (FORCE | FORCE_ALL) && - !is_authorized(DEVICE_REVOKE_AUTH, getuid())) - return (NOTAUTH); - if (optflg & FORCE_ALL) - optflg |= FORCE; - - setdaent(); - setdmapent(); + int len = 0; + char *zoneroot; + char **file; + char zonepath[MAXPATHLEN]; + + file = dm->dmap_devarray; + if (file == NULL) + return (NODMAPERR); + if ((zoneroot = getzonerootbyname(zonename)) == NULL) { + (void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename); + } else { + char *p; - 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); + 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; + + /* + * 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); +} - 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); - } +int +update_device(char **devnames, char *zonename, int flag) +{ + int len, rc; + char *optstr = NULL; + da_args dargs; + devinfo_t devinfo; + + 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); } diff --git a/usr/src/cmd/allocate/audio_clean.c b/usr/src/cmd/allocate/audio_clean.c index 4447fdf012..24753b8569 100644 --- a/usr/src/cmd/allocate/audio_clean.c +++ b/usr/src/cmd/allocate/audio_clean.c @@ -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) -{ - 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) +usage(char *prog) { - 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 @@ main(int argc, char *argv[]) * 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 @@ main(int argc, char *argv[]) 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); - exit(1); } - if (strlen(argv[0]) > (BUF_SIZE - sizeof (DMINFO) - 2)) { - (void) fprintf(stderr, gettext("device name %s too long\n"), - argv[0]); + if ((argc - optind) != 1) { + if (verbose) + usage(prog); 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 @@ main(int argc, char *argv[]) if (verbose) (void) fprintf(stderr, gettext("%s: %s is not an audio device\n"), prog, - Audio_dev); + devpath); exit(1); } @@ -222,26 +196,18 @@ main(int argc, char *argv[]) * 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 @@ main(int argc, char *argv[]) if (ioctl(Audio_fd, AUDIO_GETINFO, &info) != 0) { perror("Ioctl AUDIO_GETINFO error"); + (void) close(Audio_fd); exit(1); } @@ -265,12 +232,14 @@ main(int argc, char *argv[]) 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); } diff --git a/usr/src/cmd/dminfo/dminfo.c b/usr/src/cmd/allocate/dminfo.c index b1dc7ea49f..1a2d035e0a 100644 --- a/usr/src/cmd/dminfo/dminfo.c +++ b/usr/src/cmd/allocate/dminfo.c @@ -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,19 +18,15 @@ * * 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" -#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 <stdlib.h> #include <string.h> #include <string.h> #include <unistd.h> @@ -70,7 +65,7 @@ printdmapent(dmapp) { (void) printf("%s:", dmapp->dmap_devname); (void) printf("%s:", dmapp->dmap_devtype); - (void) printf("%s:", dmapp->dmap_devlist); + (void) printf("%s", dmapp->dmap_devlist); (void) printf("\n"); } @@ -82,9 +77,7 @@ printdmapent(dmapp) * */ static void -dmapi_err(exit_code, err_msg) -int exit_code; -char *err_msg; +dmapi_err(int exit_code, char *err_msg) { if (err_msg != NULL) { (void) fprintf(stderr, "dmapinfo:%s\n", err_msg); @@ -107,12 +100,12 @@ char *err_msg; prog_name, "[-u Entry]"); } + exit(exit_code); } - int -main(int argc, char *argv[]) +main(int argc, char **argv) { devmap_t *dmapp; devmap_t dmap; @@ -227,12 +220,12 @@ main(int argc, char *argv[]) dmapi_err(EINVOKE, gettext("Bad dmap_devname in entry argument")); } - if ((dmap.dmap_devtype = getdmapfield((char *)NULL)) == + if ((dmap.dmap_devtype = getdmapfield(NULL)) == NULL) { dmapi_err(EINVOKE, gettext("Bad dmap_devtype in entry Argument")); } - if ((dmap.dmap_devlist = getdmapfield((char *)NULL)) == + if ((dmap.dmap_devlist = getdmapfield(NULL)) == NULL) { dmapi_err(EINVOKE, gettext("Bad dmap_devlist in entry argument")); @@ -319,21 +312,27 @@ main(int argc, char *argv[]) nptr = getdmapdfield(nptr); while (nptr) { if (verbose) { -(void) fprintf(stderr, gettext("dmapinfo: Check %s for device (%s).\n"), - filename, nptr); + (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); + (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); + (void) fprintf(stderr, + gettext("dmapinfo: " + "Device (%s) not found in %s.\n"), + nptr, filename); } - nptr = getdmapdfield((char *)NULL); + nptr = getdmapdfield(NULL); } /* * Good the entry is uniq. So lets find out how long it is @@ -390,17 +389,21 @@ main(int argc, char *argv[]) * of 1. */ if (device) { + setdmapent(); while (argc >= 1) { if ((dmapp = getdmapdev(*argv)) != NULL) { if (verbose) { printdmapent(dmapp); } cntr++; - } else if (any == 0) + } else if (any == 0) { + enddmapent(); exit(1); + } argc--; argv++; } + enddmapent(); if (cntr != 0) exit(0); exit(1); @@ -413,6 +416,7 @@ main(int argc, char *argv[]) * of 1. */ if (name) { + setdmapent(); while (argc >= 1) { if ((dmapp = getdmapnam(*argv)) != NULL) { if (verbose) { @@ -424,6 +428,7 @@ main(int argc, char *argv[]) argc--; argv++; } + enddmapent(); if (cntr != 0) exit(0); exit(1); @@ -438,20 +443,22 @@ main(int argc, char *argv[]) */ if (tp) { cntr = 0; + setdmapent(); while (argc >= 1) { - setdmapent(); while ((dmapp = getdmaptype(*argv)) != 0) { cntr++; if (verbose) { printdmapent(dmapp); } } - enddmapent(); - if ((any == 0) && (cntr == 0)) + if ((any == 0) && (cntr == 0)) { + enddmapent(); exit(1); + } argc--; argv++; } + enddmapent(); if (cntr == 0) exit(1); exit(0); diff --git a/usr/src/cmd/allocate/mkdevalloc.c b/usr/src/cmd/allocate/mkdevalloc.c index 50c58af3eb..e423e3727a 100644 --- a/usr/src/cmd/allocate/mkdevalloc.c +++ b/usr/src/cmd/allocate/mkdevalloc.c @@ -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 @@ struct tape { #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 @@ struct audio { } *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 @@ struct cd { #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 @@ struct fp { #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 @@ dotape() { 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 @@ dotape() 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 @@ doaudio() { 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 @@ doaudio() (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 @@ dofloppy() { 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 @@ dofloppy() (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 @@ docd() 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 @@ docd() 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 @@ docd() i++; } - n = i; + cd_count = i; (void) closedir(dirp); @@ -616,7 +899,7 @@ docd() 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 @@ found: 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,19 +984,256 @@ found1: (void) closedir(dirp); - n = i; + cd_count = i; + + 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 < 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; - /* print out device_maps entries for tape devices */ 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 < 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 @@ initmem() 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) */ diff --git a/usr/src/cmd/auditconfig/auditconfig.c b/usr/src/cmd/auditconfig/auditconfig.c index 46d42cd346..57c6f7d53b 100644 --- a/usr/src/cmd/auditconfig/auditconfig.c +++ b/usr/src/cmd/auditconfig/auditconfig.c @@ -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 arg_entry { struct policy_entry { char *policy_str; uint_t policy_mask; + uint_t policy_flags; char *policy_desc; }; @@ -236,27 +243,40 @@ static struct arg_entry arg2_table[] = { #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 @@ main(argc, argv) strcmp(argv[1], "-?") == 0)) exit_usage(0); + tsol_on = is_system_labeled(); + parse_args(argv); do_args(argv); @@ -1246,6 +1268,15 @@ do_audit(event, sorf, retval, audit_str) "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 @@ do_lspolicy() * 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 @@ get_policy_ent(policy) { 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 @@ policy2str(policy, policy_str, len) *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 @@ policy2str(policy, policy_str, len) (void) strlcat(policy_str, policy_table[i].policy_str, len); } + } if (*policy_str) return (0); diff --git a/usr/src/cmd/auditreduce/Makefile b/usr/src/cmd/auditreduce/Makefile index 7d10fd2a1a..b63b6c9f35 100644 --- a/usr/src/cmd/auditreduce/Makefile +++ b/usr/src/cmd/auditreduce/Makefile @@ -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 @@ POFILE=auditreduce.po 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: diff --git a/usr/src/cmd/auditreduce/auditr.h b/usr/src/cmd/auditreduce/auditr.h index 61462030e6..de5e26bc90 100644 --- a/usr/src/cmd/auditreduce/auditr.h +++ b/usr/src/cmd/auditreduce/auditr.h @@ -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 @@ extern "C" { #include <bsm/audit_record.h> #include <bsm/libbsm.h> +#include <tsol/label.h> +#include <sys/tsol/label_macro.h> + #include "auditrt.h" /* diff --git a/usr/src/cmd/auditreduce/auditrd.h b/usr/src/cmd/auditreduce/auditrd.h index 22f65b775a..bcd498c7b8 100644 --- a/usr/src/cmd/auditreduce/auditrd.h +++ b/usr/src/cmd/auditreduce/auditrd.h @@ -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_after; /* 'a' after a time */ 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; diff --git a/usr/src/cmd/auditreduce/auditrt.h b/usr/src/cmd/auditreduce/auditrt.h index d929030233..f013cbfb99 100644 --- a/usr/src/cmd/auditreduce/auditrt.h +++ b/usr/src/cmd/auditreduce/auditrt.h @@ -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 time_t m_before; /* 'b' before a time */ 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; diff --git a/usr/src/cmd/auditreduce/option.c b/usr/src/cmd/auditreduce/option.c index 181a383ad4..f4aaa9d726 100644 --- a/usr/src/cmd/auditreduce/option.c +++ b/usr/src/cmd/auditreduce/option.c @@ -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_group(char *, gid_t *); 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 @@ start_over: 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 @@ proc_pcb(audit_pcb_t *pcb, char *suffix, int i) } -#ifdef TSOL /* * .func proc_slabel - process sensitivity label range argument. * .desc Parse sensitivity label range sl:sl @@ -1157,67 +1152,101 @@ proc_slabel(char *optstr) error_str = gettext("'l' option specified multiple times"); return (-1); } - 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. diff --git a/usr/src/cmd/auditreduce/token.c b/usr/src/cmd/auditreduce/token.c index 7b3c75ea24..f47c1e4cf0 100644 --- a/usr/src/cmd/auditreduce/token.c +++ b/usr/src/cmd/auditreduce/token.c @@ -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 @@ xclient_token(adr_t *adr) } /* - * 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 @@ privilege_token(adr_t *adr) * 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 */ } diff --git a/usr/src/cmd/bsmconv/bsmconv.sh b/usr/src/cmd/bsmconv/bsmconv.sh index ca0856d333..db037c5b20 100644 --- a/usr/src/cmd/bsmconv/bsmconv.sh +++ b/usr/src/cmd/bsmconv/bsmconv.sh @@ -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,19 +142,26 @@ then 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 -fi -if [ ! -f $DEVMAPS ] -then - mkdevmaps > ${ROOT}/$DEVMAPS + # 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 + # enable auditd. Since we're running as single user, auditd won't # actually start until reboot. diff --git a/usr/src/cmd/bsmunconv/bsmunconv.sh b/usr/src/cmd/bsmunconv/bsmunconv.sh index 0e06c4619f..85661b6d7a 100644 --- a/usr/src/cmd/bsmunconv/bsmunconv.sh +++ b/usr/src/cmd/bsmunconv/bsmunconv.sh @@ -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 @@ fi 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 diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile b/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile index e4fdbd84da..5e52d8c1ac 100644 --- a/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile +++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile @@ -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 @@ COMMONSRCS= $(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c) 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: diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c index f978ae489e..8218eac44d 100644 --- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c +++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c @@ -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 mib_item_t *mib_item_diff(mib_item_t *item1, 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 @@ static char *pr_addr6(const in6_addr_t *addr, 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 *fmodestr(uint_t fmode); 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_ip4(mib2_ipAddrEntry_t *ap, 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_udp_stats(mib2_udp_t *udp); 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 Iflag = B_FALSE; /* IP Traffic Interfaces */ 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 ipRouteEntrySize; static int ipNetToMediaEntrySize; static int ipMemberEntrySize; static int ipGroupSourceEntrySize; +static int ipRouteAttributeSize; static int vifctlSize; static int mfcctlSize; @@ -265,6 +269,7 @@ static int ipv6NetToMediaEntrySize; static int ipv6MemberEntrySize; static int ipv6GroupSourceEntrySize; +static int transportMLPSize; static int tcpConnEntrySize; static int tcp6ConnEntrySize; static int udpEntrySize; @@ -362,7 +367,7 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) } /* + * 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 @@ octetstrmatch(const Octet_t *a, const Octet_t *b) /* 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 @@ octetstr(Octet_t *op, int code, char *dst, uint_t dstlen) 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 @@ static char tcpsbuf[50]; 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 @@ mib_get_constants(mib_item_t *item) 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 @@ mib_get_constants(mib_item_t *item) 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 @@ mib_get_constants(mib_item_t *item) (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 @@ mib_get_constants(mib_item_t *item) 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 @@ ndp_report(mib_item_t *item) /* ------------------------- 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 @@ ire_report(mib_item_t *item) /* 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 @@ ire_report(mib_item_t *item) /* 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 @@ v4_addr_match(IpAddress addr, IpAddress mask, const filter_t *fp) * 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 @@ ire_filter_match_v4(mib2_ipRouteEntry_t *rp, uint_t flag_b) * 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 @@ form_v4_route_flags(mib2_ipRouteEntry_t *rp, char *flags) 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 @@ ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first) 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 @@ ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first) } 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 @@ ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first) 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 @@ ire_report_item_v4src(mib2_ipRouteEntry_t *rp, boolean_t first) 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 @@ ire_report_item_v4src(mib2_ipRouteEntry_t *rp, boolean_t first) (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 @@ v6_addr_match(const Ip6Address *addr, int masklen, const filter_t *fp) * 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 @@ ire_filter_match_v6(mib2_ipv6RouteEntry_t *rp6, uint_t flag_b) 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 @@ ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6, boolean_t first) 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 @@ ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6, boolean_t first) 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 @@ ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6, boolean_t first) 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 @@ static const char tcp_hdr_v4_compat[] = "\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 @@ tcp_report(mib_item_t *item) /* 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 @@ tcp_report(mib_item_t *item) /* 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 @@ tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first) 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 @@ tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first) 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 @@ tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first) (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 @@ tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first) 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 @@ tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first) 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 @@ tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first) (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 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 char *udp_hdr_v6 = +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 @@ udp_report(mib_item_t *item) /* 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 @@ udp_report(mib_item_t *item) /* 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 sctp_hdr_normal[] = "------ ------ ------ ------ ------- -----------"; 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 @@ sctp_getnext_rem(mib_item_t **itemp, mib2_sctpConnRemoteEntry_t *current, 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 @@ sctp_getnext_rem(mib_item_t **itemp, mib2_sctpConnRemoteEntry_t *current, 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 @@ sctp_getnext_local(mib_item_t **itemp, mib2_sctpConnLocalEntry_t *current, 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 @@ sctp_pr_addr(int type, char *name, int namelen, const in6_addr_t *addr, } 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 @@ sctp_conn_report_item(mib_item_t *head, mib2_sctpConnEntry_t *sp) 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 @@ sctp_conn_report_item(mib_item_t *head, mib2_sctpConnEntry_t *sp) } 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 @@ sctp_report(mib_item_t *item) 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 @@ sctp_report(mib_item_t *item) (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 @@ pr_mask(uint_t addr, char *dst, uint_t dstlen) * 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 @@ fmodestr(uint_t fmode) } } +#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 @@ usage(char *cmdname) */ /*PRINTFLIKE2*/ static void -fatal(int errcode, char *format, ...) { +fatal(int errcode, char *format, ...) +{ va_list argp; if (format == NULL) diff --git a/usr/src/cmd/cmd-inet/usr.sbin/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/Makefile index af9d3a9571..efb96c714b 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile @@ -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 @@ NSLPROG= 6to4relay arp gettable hostconfig ikeadm in.comsat in.rarpd \ 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 @@ $(K5PROGS) := CPPFLAGS += -I$(SRC)/head \ -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: $(LINTSUBDIRS) $(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 diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c index ee577669b0..162a64a326 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c @@ -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 set_tun_encap_limit(char *arg, int64_t param); 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 @@ struct cmd { { "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 @@ setzone(char *arg, int64_t param) 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 @@ ifstatus(const char *ifname) 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 @@ usage(void) "\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, diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c index 1c81d646f8..d23133c029 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/table.c @@ -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 @@ read_rt(void) * 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 @@ rt_xaddrs(struct rt_addrinfo *info, 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: diff --git a/usr/src/cmd/cmd-inet/usr.sbin/route.c b/usr/src/cmd/cmd-inet/usr.sbin/route.c index 18044d9d18..431d92dee3 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/route.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c @@ -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 @@ static struct keytab { {"setsrc", K_SETSRC}, #define K_SHOW 43 {"show", K_SHOW}, +#define K_SECATTR 43 + {"secattr", K_SECATTR}, {0, 0} }; @@ -206,14 +213,16 @@ typedef struct rtcmd_irep { 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 mib_item_t *mibget(int sd); 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_bad_keyword(char *keyword); 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 int exit_on_error = B_TRUE; static struct { struct rt_msghdr m_rtm; - char m_space[512]; + char m_space[BUF_SIZE]; } m_rtmsg; /* @@ -337,7 +347,6 @@ static int ipv6RouteEntrySize; #define BAD_ADDR -1 /* prefix is invalid */ #define NO_PREFIX -2 /* no prefix was found */ - void usage(char *cp) { @@ -408,7 +417,7 @@ main(int argc, char **argv) (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 @@ main(int argc, char **argv) break; case '?': default: - usage((char *)NULL); + usage(NULL); /* NOTREACHED */ } } @@ -815,7 +824,7 @@ delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) * 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 @@ args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) } 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 @@ rtmsg(rtcmd_irep_t *newrt) */ 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 @@ print_rtmsg(struct rt_msghdr *rtm, int msglen) 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 @@ print_rtmsg(struct rt_msghdr *rtm, int msglen) 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 @@ print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) (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 @@ sockaddr(char *addr, struct sockaddr *sa) } int -salen(struct sockaddr *sa) +salen(const struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: @@ -3094,3 +3177,57 @@ mibget(int sd) } 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))); + } +} diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile index e9dc9a374f..d853d7f37f 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile @@ -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 @@ HDRS= snoop.h snoop_mip.h at.h snoop_ospf.h snoop_ospf6.h 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: diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c index 3b5e49bb39..386fcbce85 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c @@ -53,7 +53,7 @@ #include "snoop.h" -int snaplen; +static int snaplen; char *device = NULL; /* Global error recovery variables */ @@ -61,12 +61,9 @@ sigjmp_buf jmp_env, ojmp_env; /* error recovery jmp buf */ 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 *detail_line; 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 @@ boolean_t zflg = B_FALSE; /* debugging packet corrupt flag */ #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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) /* 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) net_read(chunksize, filter, proc, flags); if (!(flags & F_NOW)) - printf("\n"); + (void) printf("\n"); } if (ocapfile) @@ -500,7 +493,7 @@ main(int argc, char **argv) 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 @@ click(len) len = len ? len : 4; if (audio) { - write(audio, tone, len); + (void) write(audio, tone, len); } } @@ -561,16 +554,16 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len) 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 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len) 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 @@ get_detail_line(off, len) 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 @@ get_detail_line(off, len) /* * 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 @@ pr_err(char *fmt, ...) *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 @@ pr_err(char *fmt, ...) * 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 @@ snoop_alarm(int s_sec, void (*s_handler)()) 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_alarm(int s_sec, void (*s_handler)()) 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 @@ snoop_recover(void) * 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 @@ snoop_sigrecover(int sig, siginfo_t *info, void *p) /* Setup next alarm */ if (nalarm) { snoop_nalarm = nalarm; - alarm(nalarm - now); + (void) alarm(nalarm - now); } else { snoop_nalarm = 0; } @@ -979,7 +978,7 @@ snoop_sigrecover(int sig, siginfo_t *info, void *p) 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 @@ snoop_sigrecover(int sig, siginfo_t *info, void *p) 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 @@ snoop_sigrecover(int sig, siginfo_t *info, void *p) 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); } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h index c78f3c9f31..fe9bf31253 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h @@ -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 *prot_nest_prefix; 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 char *concat_args(char **, int); 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_pktinfo(int, int, char *, char *, struct timeval *, 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_solarnet_fw(int, int, int, int, int, char *, int); 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 *device; 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. diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c index 2270229884..e3e7bd75fd 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c @@ -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 */ - -extern unsigned int encap_levels; +static int netfd; +static union DL_primitives netdl; /* info_ack for interface */ +static char *bufp; /* pointer to read buffer */ -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 @@ device_ppa(device) * 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 @@ check_device(char **devicep, int *ppap) /* 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 @@ check_device(char **devicep, int *ppap) * 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 @@ initdevice(device, snaplen, chunksize, timeout, fp, ppa) struct Pf_ext_packetfilt *fp; int ppa; { - union DL_primitives dl; extern int Pflg; /* @@ -281,7 +290,7 @@ initdevice(device, snaplen, chunksize, timeout, fp, ppa) 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 @@ initdevice(device, snaplen, chunksize, timeout, fp, ppa) * 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 @@ initdevice(device, snaplen, chunksize, timeout, fp, ppa) * 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 @@ net_read(chunksize, filter, proc, flags) } free(bufp); - close(netfd); + (void) close(netfd); if (!quitting) { if (r < 0) @@ -422,13 +431,9 @@ corrupt(volatile char *pktp, volatile char *pstop, char *buf, } #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 @@ scan(buf, len, filter, cap, old, proc, first, last, flags) * capture file, convert the header. */ if (old) { - convert_old(hdrp); + convert_old((struct ohdr *)hdrp); } nhdrp = &nhdr; @@ -685,34 +690,33 @@ static int capfile_out; * | 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_open_read(name) 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 @@ cap_read(first, last, filter, proc, flags) 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 @@ cap_write(hdrp, pktp, num, flags) static int first = 1; struct sb_hdr nhdr; extern boolean_t qflg; - int rc; if (hdrp == NULL) return; @@ -831,7 +835,7 @@ cap_write(hdrp, pktp, num, flags) 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 @@ cap_write(hdrp, pktp, num, flags) 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 @@ cap_write(hdrp, pktp, num, flags) } /* - * 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 @@ convert_old(ohdrp) } 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; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c index 3ca7d44ccf..f188a242a8 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcp.c @@ -135,7 +135,7 @@ static char *option_types[] = { #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) && diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c index 8421eccda6..be6440a525 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c @@ -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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) * 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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) 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 @@ interpret_ip(flags, ip, fraglen) } 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 @@ interpret_ipv6(flags, ip6h, fraglen) * 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 @@ interpret_ipv6(flags, ip6h, fraglen) 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 @@ interpret_ipv6(flags, ip6h, fraglen) 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 @@ interpret_ipv6(flags, ip6h, fraglen) 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 @@ interpret_ipv6(flags, ip6h, fraglen) 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 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, * header. */ if (*fraglen < 2) { - proto = IPPROTO_NONE; return (extmask); } @@ -527,7 +527,6 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 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 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 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 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 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 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 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 @@ print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, } 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 @@ print_ipoptions(opt, optlen) } 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 @@ print_route(opt) 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 @@ print_route(opt) } char * -getproto(p) - int p; +getproto(int p) { switch (p) { case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); @@ -728,9 +739,7 @@ getproto(p) } 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 @@ prt_routing_hdr(flags, ipv6ext_rthdr) 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 @@ prt_routing_hdr(flags, ipv6ext_rthdr) * 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 @@ prt_routing_hdr(flags, ipv6ext_rthdr) } 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 @@ prt_fragment_hdr(flags, ipv6ext_frag) 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 @@ prt_fragment_hdr(flags, ipv6ext_frag) 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 @@ prt_fragment_hdr(flags, ipv6ext_frag) } 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 @@ prt_hbh_options(flags, ipv6ext_hbh) */ 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 @@ prt_hbh_options(flags, ipv6ext_hbh) } 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 @@ prt_dest_options(flags, ipv6ext_dest) */ 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); + 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++; } - /* 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); + 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; } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c index 45061e5cf7..1f7a743ff4 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipaddr.c @@ -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 hostdata6 { 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 @@ iplookup(struct in_addr ipaddr) } 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 @@ ip6lookup(struct in6_addr *ip6addr) } 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 @@ addhost(int family, void *ipaddr, char *name, char **aliases) 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 @@ addhost(int family, void *ipaddr, char *name, char **aliases) 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 @@ addhost(int family, void *ipaddr, char *name, char **aliases) 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 @@ alloc_failed: } 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 @@ load_names(fname) 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); diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c index a8c248cfbd..76ec01f0c0 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ipsec.c @@ -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 @@ interpret_esp(int flags, uint8_t *hdr, int iplen, int fraglen) 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 @@ interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen) 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 @@ interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen) if (fraglen > 0) switch (proto) { case IPPROTO_ENCAP: + /* LINTED: alignment */ (void) interpret_ip(flags, (struct ip *)data, new_iplen); break; @@ -205,27 +207,33 @@ interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen) 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); + (void) interpret_esp(flags, data, new_iplen, + fraglen); break; + case IPPROTO_AH: - interpret_ah(flags, data, new_iplen, fraglen); + (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 */ } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c index 91ff5be13f..c8a897c95e 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c @@ -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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) } 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) } 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) 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 @@ interpret_rip(int flags, struct rip *rip, int fraglen) return (fraglen - len); } -static char * +static const char * show_cmd(int c) { switch (c) { @@ -315,6 +397,44 @@ show_cmd(int c) 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); +} diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c index 8a65afda5d..9722ee24d5 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c @@ -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 @@ getportname(int proto, in_port_t port) 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 @@ reservedport(int proto, int port) * 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 @@ interpret_syslog(int flags, char dir, int port, const char *syslogstr, 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 @@ interpret_syslog(int flags, char dir, int port, const char *syslogstr, 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 @@ int 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 @@ interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst, 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 @@ interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst, * 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 @@ interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst, 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 @@ show_string(const char *str, int dlen, int maxlen) *pp++ = c; printable++; } else { - (void) sprintf(pp, + (void) snprintf(pp, TBSIZE - (pp - tbuff), isdigit(*(p + 1)) ? "\\%03o" : "\\%o", c); pp += strlen(pp); diff --git a/usr/src/cmd/devfsadm/Makefile.com b/usr/src/cmd/devfsadm/Makefile.com index a07e7031df..247e1cb0fa 100644 --- a/usr/src/cmd/devfsadm/Makefile.com +++ b/usr/src/cmd/devfsadm/Makefile.com @@ -32,12 +32,15 @@ COMMON = .. 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_USED_NOT_DEF2 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) diff --git a/usr/src/cmd/devfsadm/audio_link.c b/usr/src/cmd/devfsadm/audio_link.c index 2f898e35f5..75568ff46e 100644 --- a/usr/src/cmd/devfsadm/audio_link.c +++ b/usr/src/cmd/devfsadm/audio_link.c @@ -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 @@ minor_fini(void) 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 @@ audio_process(di_minor_t minor, di_node_t node) 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 @@ check_audio_link(char *secondary_link, const char *primary_link_format) { 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; } } diff --git a/usr/src/cmd/devfsadm/devalloc.c b/usr/src/cmd/devfsadm/devalloc.c new file mode 100644 index 0000000000..413d617883 --- /dev/null +++ b/usr/src/cmd/devfsadm/devalloc.c @@ -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); + } +} diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 75ed42f4c4..c3904792e3 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -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> +#include "devfsadm_impl.h" -/* globals */ +/* 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 @@ static int cleanup = FALSE; /* devlinks -d compatibility */ static int devlinks_debug = FALSE; -/* turn off device allocation with devfsadm -d */ -static int devalloc_off = FALSE; +/* 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}; -/* devices to be deallocated with -d */ -static char *devalloc[5] = - {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_FD, DDI_NT_TAPE, 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 @@ static void update_drvconf(major_t); int main(int argc, char *argv[]) { + struct stat tx_stat; struct passwd *pw; struct group *gp; pid_t pid; @@ -251,10 +274,26 @@ main(int argc, char *argv[]) (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 @@ main(int argc, char *argv[]) (void) rcm_init(); login_dev_enable = TRUE; } - daemon_update(); } else { err_print(DAEMON_RUNNING, pid); @@ -322,6 +360,9 @@ main(int argc, char *argv[]) } 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 @@ parse_args(int argc, char *argv[]) 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 @@ parse_args(int argc, char *argv[]) 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 @@ devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) 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 @@ process_devinfo_tree() } 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_mklink_default(char *link, di_node_t node, di_minor_t minor, int flags) == 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 @@ devfsadm_secondary_link(char *link, char *primary_link, int flags) */ 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 @@ set_logindev_perms(char *devlink) 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 @@ reset_node_permissions(di_node_t node, di_minor_t minor) } /* - * 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 @@ reset_node_permissions(di_node_t node, di_minor_t minor) 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 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass, } } + /* 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 @@ int 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 @@ devfsadm_link_valid(char *link) * 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); diff --git a/usr/src/cmd/devfsadm/disk_link.c b/usr/src/cmd/devfsadm/disk_link.c index 57805e655e..f12f9cfb0d 100644 --- a/usr/src/cmd/devfsadm/disk_link.c +++ b/usr/src/cmd/devfsadm/disk_link.c @@ -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 @@ disk_common(di_minor_t minor, di_node_t node, char *disk, int flags) 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 @@ disk_common(di_minor_t minor, di_node_t node, char *disk, int flags) } (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, "^"); diff --git a/usr/src/cmd/devfsadm/i386/misc_link_i386.c b/usr/src/cmd/devfsadm/i386/misc_link_i386.c index 484214dfa7..1e400531bc 100644 --- a/usr/src/cmd/devfsadm/i386/misc_link_i386.c +++ b/usr/src/cmd/devfsadm/i386/misc_link_i386.c @@ -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 @@ vt00(di_minor_t minor, di_node_t node) 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 @@ diskette(di_minor_t minor, di_node_t node) 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); } } } diff --git a/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c b/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c index ee2c059b24..0d0aa692bd 100644 --- a/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c +++ b/usr/src/cmd/devfsadm/sparc/misc_link_sparc.c @@ -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 @@ ddi_other(di_minor_t minor, di_node_t node) 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); diff --git a/usr/src/cmd/devfsadm/tape_link.c b/usr/src/cmd/devfsadm/tape_link.c index 2aae4a4406..cd532d22e9 100644 --- a/usr/src/cmd/devfsadm/tape_link.c +++ b/usr/src/cmd/devfsadm/tape_link.c @@ -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 @@ DEVFSADM_REMOVE_INIT_V0(tape_remove_cbt); 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 @@ tape_process(di_minor_t minor, di_node_t node) (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); } diff --git a/usr/src/cmd/devfsadm/usb_link.c b/usr/src/cmd/devfsadm/usb_link.c index 53f03806a0..5012d8ae40 100644 --- a/usr/src/cmd/devfsadm/usb_link.c +++ b/usr/src/cmd/devfsadm/usb_link.c @@ -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 @@ usb_process(di_minor_t minor, di_node_t node) 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 @@ usb_process(di_minor_t minor, di_node_t node) 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 @@ ugen_create_link(char *p_path, char *node_name, 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 @@ ugen_create_link(char *p_path, char *node_name, 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); } diff --git a/usr/src/cmd/fs.d/autofs/auto_subr.c b/usr/src/cmd/fs.d/autofs/auto_subr.c index 28f8cf56a5..c92eef690d 100644 --- a/usr/src/cmd/fs.d/autofs/auto_subr.c +++ b/usr/src/cmd/fs.d/autofs/auto_subr.c @@ -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 @@ struct mntlist *current_mounts; 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 @@ dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack, 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) diff --git a/usr/src/cmd/fs.d/autofs/autod_lookup.c b/usr/src/cmd/fs.d/autofs/autod_lookup.c index a4abbbef97..a70541b30c 100644 --- a/usr/src/cmd/fs.d/autofs/autod_lookup.c +++ b/usr/src/cmd/fs.d/autofs/autod_lookup.c @@ -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 @@ do_lookup1(mapname, key, subdir, mapopts, path, isdirect, action, linkp, cred) char *stack[STACKSIZ]; char **stkptr = stack; -#ifdef lint - path = path; -#endif /* lint */ - /* * Default action is for no work to be done by kernel AUTOFS. */ diff --git a/usr/src/cmd/fs.d/autofs/autod_main.c b/usr/src/cmd/fs.d/autofs/autod_main.c index 7bcf02d127..ce57a1fc80 100644 --- a/usr/src/cmd/fs.d/autofs/autod_main.c +++ b/usr/src/cmd/fs.d/autofs/autod_main.c @@ -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 @@ main(argc, argv) /* 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); diff --git a/usr/src/cmd/fs.d/autofs/autod_nfs.c b/usr/src/cmd/fs.d/autofs/autod_nfs.c index dc5cf60c7f..741eba369c 100644 --- a/usr/src/cmd/fs.d/autofs/autod_nfs.c +++ b/usr/src/cmd/fs.d/autofs/autod_nfs.c @@ -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 @@ static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *, 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 @@ add_mfs(struct mapfs *mfs, int distance, struct mapfs **mfs_head, 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 @@ try_mnt_slash: } /* 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 @@ try_mnt_slash: else sl = service_list; - _check_services(sl); + (void) _check_services(sl); } /* @@ -3598,6 +3614,13 @@ loopbackmount(fsname, dir, mntopts, overlay) " 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 @@ is_v4_mount(char *mntpath) 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); +} diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c b/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c index 358b4f56c6..b761e47bc6 100644 --- a/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c +++ b/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c @@ -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 @@ struct conn_entry { */ 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 @@ nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 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 @@ nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 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 @@ nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 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 @@ nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, } 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 @@ reuseaddr(int fd) 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) { diff --git a/usr/src/cmd/fs.d/nfs/mountd/mountd.c b/usr/src/cmd/fs.d/nfs/mountd/mountd.c index dda4b78700..2ae1d1e38e 100644 --- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c +++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c @@ -112,6 +112,7 @@ main(int argc, char *argv[]) int maxthreads; int maxrecsz = RPC_MAXDATASIZE; bool_t exclbind = TRUE; + bool_t can_do_mlp; /* * Mountd requires uid 0 for: @@ -123,10 +124,13 @@ main(int argc, char *argv[]) * 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 @@ mount(struct svc_req *rqstp) } /* + * 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) { diff --git a/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c b/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c index 791fad6997..818552f821 100644 --- a/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c +++ b/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c @@ -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 @@ main(int ac, char *av[]) NETSELDECL(df_proto) = NULL; NETSELPDECL(providerp); char *defval; + boolean_t can_do_mlp; MyName = *av; @@ -146,8 +146,10 @@ main(int ac, char *av[]) (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); diff --git a/usr/src/cmd/fs.d/nfs/statd/sm_svc.c b/usr/src/cmd/fs.d/nfs/statd/sm_svc.c index f90ec07960..a3dca0ca5f 100644 --- a/usr/src/cmd/fs.d/nfs/statd/sm_svc.c +++ b/usr/src/cmd/fs.d/nfs/statd/sm_svc.c @@ -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 @@ main(int argc, char *argv[]) */ 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 @@ set_statmon_owner() 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); } diff --git a/usr/src/cmd/ldap/Makefile.com b/usr/src/cmd/ldap/Makefile.com index 824788ffd3..d65d341a22 100644 --- a/usr/src/cmd/ldap/Makefile.com +++ b/usr/src/cmd/ldap/Makefile.com @@ -1,4 +1,24 @@ # +# 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 @@ LDAPLISTOBJS= $(LDAPLISTSRCS:%.c=%.o) # 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 @@ clobber:= TARGET= clobber 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 @@ ldapsearch := LDLIBS += -lldap 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 diff --git a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh index 645dfb7c73..485c5f9c7e 100644 --- a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh +++ b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh @@ -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.18.0.2.4.1108 NAME 'printer-aliases' DESC 'Site-specific ad 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 @@ dn: cn=schema 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 @@ add_new_containers() 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}" diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c index a5d420e406..7b30890fde 100644 --- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c +++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c @@ -3572,6 +3572,10 @@ static struct ttypelist_t ttypelist[] = { 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 @@ dumptable(char *service) (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); diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddent.h b/usr/src/cmd/ldap/ns_ldap/ldapaddent.h index 6da82f1fe9..42973d2c6a 100644 --- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.h +++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.h @@ -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_prof_attr(char *line, int (*cback)()); 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 } diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c b/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c index 04da2f7b66..63c065ea7d 100644 --- a/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c +++ b/usr/src/cmd/ldap/ns_ldap/ldapaddrbac.c @@ -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 @@ extern char *_strtok_escape(char *, char *, char **); /* from libnsl */ * 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 */ diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddtsol.c b/usr/src/cmd/ldap/ns_ldap/ldapaddtsol.c new file mode 100644 index 0000000000..985a859173 --- /dev/null +++ b/usr/src/cmd/ldap/ns_ldap/ldapaddtsol.c @@ -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'); +} diff --git a/usr/src/cmd/ldap/ns_ldap/mapping.c b/usr/src/cmd/ldap/ns_ldap/mapping.c index 57827c6f74..470ca20628 100644 --- a/usr/src/cmd/ldap/ns_ldap/mapping.c +++ b/usr/src/cmd/ldap/ns_ldap/mapping.c @@ -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 @@ static struct mapping maplist[] = { {"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 @@ printMapping() "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); } } diff --git a/usr/src/cmd/lp/cmd/Makefile b/usr/src/cmd/lp/cmd/Makefile index 9bffdde5f0..2a50a58144 100644 --- a/usr/src/cmd/lp/cmd/Makefile +++ b/usr/src/cmd/lp/cmd/Makefile @@ -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 @@ accept:= LDLIBS += $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBLP) 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: diff --git a/usr/src/cmd/lp/cmd/adaptor/Makefile b/usr/src/cmd/lp/cmd/adaptor/Makefile index 5fc1aadfb6..f7d7d7508b 100644 --- a/usr/src/cmd/lp/cmd/adaptor/Makefile +++ b/usr/src/cmd/lp/cmd/adaptor/Makefile @@ -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 @@ ROOTLIBDIR= $(ROOT)/usr/lib/print/bsd-adaptor 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 diff --git a/usr/src/cmd/lp/cmd/adaptor/cancel_job.c b/usr/src/cmd/lp/cmd/adaptor/cancel_job.c index 6ee2368049..7ffa9af79b 100644 --- a/usr/src/cmd/lp/cmd/adaptor/cancel_job.c +++ b/usr/src/cmd/lp/cmd/adaptor/cancel_job.c @@ -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 @@ cancel_requestor(const char *printer, const char *user, const char *host) 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 @@ lpsched_cancel_job(const char *printer, FILE *ofp, const char *requestor, 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")); diff --git a/usr/src/cmd/lp/cmd/adaptor/misc.c b/usr/src/cmd/lp/cmd/adaptor/misc.c index 75bec084d6..e4959df8fa 100644 --- a/usr/src/cmd/lp/cmd/adaptor/misc.c +++ b/usr/src/cmd/lp/cmd/adaptor/misc.c @@ -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 @@ lpsched_spooler_accepting_jobs(const char *printer) * 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); } diff --git a/usr/src/cmd/lp/cmd/adaptor/misc.h b/usr/src/cmd/lp/cmd/adaptor/misc.h index 24b8d7f2d6..f475468600 100644 --- a/usr/src/cmd/lp/cmd/adaptor/misc.h +++ b/usr/src/cmd/lp/cmd/adaptor/misc.h @@ -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 rcv_msg(int, ...); extern int id_no(const char *); extern char *user_name(const char *); extern char *user_host(const char *); +extern char *slabel; #endif /* _MISC_H */ diff --git a/usr/src/cmd/lp/cmd/adaptor/show_queue.c b/usr/src/cmd/lp/cmd/adaptor/show_queue.c index 04867c609b..4ed83bad82 100644 --- a/usr/src/cmd/lp/cmd/adaptor/show_queue.c +++ b/usr/src/cmd/lp/cmd/adaptor/show_queue.c @@ -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 @@ is_matched(int id, char *user, const char **list) #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 @@ job_list(const char *printer, FILE *ofp, const int type, const char **list, 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 @@ job_list(const char *printer, FILE *ofp, const int type, const char **list, 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 diff --git a/usr/src/cmd/lp/cmd/adaptor/submit_job.c b/usr/src/cmd/lp/cmd/adaptor/submit_job.c index d3bf04d571..ac6ad66fa4 100644 --- a/usr/src/cmd/lp/cmd/adaptor/submit_job.c +++ b/usr/src/cmd/lp/cmd/adaptor/submit_job.c @@ -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 @@ static void clean_string(char *ptr) } } - /* * 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 @@ mail(REQUEST *request, char *req_file, char *fmt, ...) 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 @@ mail(REQUEST *request, char *req_file, char *fmt, ...) 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 @@ lpsched_submit_job(const char *printer, const char *host, char *cf, 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 @@ lpsched_submit_job(const char *printer, const char *host, char *cf, 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 @@ lpsched_submit_job(const char *printer, const char *host, char *cf, 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 @@ lpsched_submit_job(const char *printer, const char *host, char *cf, gettext("failure to communicate with lpsched")); break; default: - mail(request, buf, gettext("Unknown error: %d"), + mail(request, buf, + gettext("Unknown error: %d"), status); break; } diff --git a/usr/src/cmd/lp/cmd/lpadmin/Makefile b/usr/src/cmd/lp/cmd/lpadmin/Makefile index c756879922..bb3c282500 100644 --- a/usr/src/cmd/lp/cmd/lpadmin/Makefile +++ b/usr/src/cmd/lp/cmd/lpadmin/Makefile @@ -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 + + # # -# 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. # +# ident "%Z%%M% %I% %E% SMI" +# # cmd/lp/cmd/lpadmin/Makefile # @@ -65,7 +66,8 @@ LPLIBS= $(LIBACC) \ SYSLIBS= -lcurses -LDLIBS += $(LPLIBS) $(SYSLIBS) $(I18N) +LDLIBS += -z lazyload -lsecdb -z nolazyload $(LPLIBS) \ + $(SYSLIBS) $(I18N) PROG= lpadmin diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_printer.c b/usr/src/cmd/lp/cmd/lpadmin/do_printer.c index f6a502f350..66ab3f2803 100644 --- a/usr/src/cmd/lp/cmd/lpadmin/do_printer.c +++ b/usr/src/cmd/lp/cmd/lpadmin/do_printer.c @@ -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 @@ extern void fromallclasses(); #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 @@ static void configure_printer (list) ); 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 @@ char *nameit (cmd) (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); +} diff --git a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c index cfe77a7db1..83560a6bf4 100644 --- a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c +++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c @@ -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 @@ extern void chkopts(), chkopts3(), exit(); +int system_labeled = 0; + int scheduler_active = 0; char *label = 0; @@ -88,6 +94,8 @@ main(int argc, char *argv[]) /*NOTREACHED*/ } + system_labeled = is_system_labeled(); + uname(&un); Local_System = strdup(un.nodename); diff --git a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h index 7c22f4e946..3e58a3b087 100644 --- a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h +++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h @@ -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 @@ extern void do_fault(), 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 , ... ); diff --git a/usr/src/cmd/lp/cmd/lpadmin/rmdest.c b/usr/src/cmd/lp/cmd/lpadmin/rmdest.c index b13555e86a..35ff27d364 100644 --- a/usr/src/cmd/lp/cmd/lpadmin/rmdest.c +++ b/usr/src/cmd/lp/cmd/lpadmin/rmdest.c @@ -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 @@ void rmdest (aclass, dest) if (STREQU(getdflt(), dest)) newdflt (NAME_NONE); + if (system_labeled) { + update_dev_dbs(dest, NULL, "REMOVE"); + } break; case MBUSY: diff --git a/usr/src/cmd/lp/cmd/lpc/process.c b/usr/src/cmd/lp/cmd/lpc/process.c index f7abe95007..ddeda2c430 100644 --- a/usr/src/cmd/lp/cmd/lpc/process.c +++ b/usr/src/cmd/lp/cmd/lpc/process.c @@ -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 @@ char *printer; *reject_reason, *request_id, *form, + *slabel, *file, *char_set, *disable_reason; @@ -366,6 +366,7 @@ char *printer; rcv_msg(R_INQUIRE_REQUEST_RANK, &status, &request_id, &user, + &slabel, &size, &date, &state, diff --git a/usr/src/cmd/lp/cmd/lpc/topq.c b/usr/src/cmd/lp/cmd/lpc/topq.c index 23ce029b80..4a5b0fccff 100644 --- a/usr/src/cmd/lp/cmd/lpc/topq.c +++ b/usr/src/cmd/lp/cmd/lpc/topq.c @@ -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 *user; 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 @@ char *machine; rcv_msg(R_INQUIRE_REQUEST, &status, &request_id, &user, + &slabel, &size, &date, &state, diff --git a/usr/src/cmd/lp/cmd/lpsched/Makefile b/usr/src/cmd/lp/cmd/lpsched/Makefile index 3012533bde..3d03c42a79 100644 --- a/usr/src/cmd/lp/cmd/lpsched/Makefile +++ b/usr/src/cmd/lp/cmd/lpsched/Makefile @@ -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 @@ LPLIBS = \ $(LIBLP) \ $(LIBSEC) -SYSLIBS= -lcurses -lgen -lcurses -lnsl +SYSLIBS= -lcurses -lgen -lcurses -lnsl -z lazyload \ + -ltsol -lsecdb -lcmd -lbsm -z nolazyload LDLIBS += $(LPLIBS) $(SYSLIBS) diff --git a/usr/src/cmd/lp/cmd/lpsched/disp1.c b/usr/src/cmd/lp/cmd/lpsched/disp1.c index 7473af6013..a551b7e2ec 100644 --- a/usr/src/cmd/lp/cmd/lpsched/disp1.c +++ b/usr/src/cmd/lp/cmd/lpsched/disp1.c @@ -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 @@ void s_print_request ( char * m, MESG * md ) 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 @@ void s_print_request ( char * m, MESG * md ) 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 @@ void s_start_change_request (char *m, MESG *md) 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 @@ void s_end_change_request(char *m, MESG *md) 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 @@ _cancel(MESG *md, char *dest, char *user, char *req_id) 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 @@ void s_inquire_request(char *m, MESG *md) 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 @@ void s_inquire_request(char *m, MESG *md) 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 @@ void s_inquire_request(char *m, MESG *md) 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 @@ void s_inquire_request_rank(char *m, MESG *md) 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 @@ void s_inquire_request_rank(char *m, MESG *md) 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 @@ void s_inquire_request_rank(char *m, MESG *md) 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 @@ void s_inquire_request_rank(char *m, MESG *md) 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 @@ reqpath(char *file, char **idnumber) 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); +} diff --git a/usr/src/cmd/lp/cmd/lpsched/dispatch.h b/usr/src/cmd/lp/cmd/lpsched/dispatch.h index cd4c55decd..d4d6e50ce5 100644 --- a/usr/src/cmd/lp/cmd/lpsched/dispatch.h +++ b/usr/src/cmd/lp/cmd/lpsched/dispatch.h @@ -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_mount_tray ( char *, MESG * ); 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[] diff --git a/usr/src/cmd/lp/cmd/lpsched/disptab.c b/usr/src/cmd/lp/cmd/lpsched/disptab.c index a9452d511a..46366a84ec 100644 --- a/usr/src/cmd/lp/cmd/lpsched/disptab.c +++ b/usr/src/cmd/lp/cmd/lpsched/disptab.c @@ -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 @@ static DISPATCH dispatch_table[] = { /* 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 @@ static char * dispatch_names[] = { "R_PAPER_CHANGED", "S_PAPER_ALLOWED", "R_PAPER_ALLOWED", +"S_PASS_PEER_CONNECTION", +"R_PASS_PEER_CONNECTION", }; /* see include/msgs.h */ diff --git a/usr/src/cmd/lp/cmd/lpsched/exec.c b/usr/src/cmd/lp/cmd/lpsched/exec.c index 579cada8f6..4dd2b8a3c7 100644 --- a/usr/src/cmd/lp/cmd/lpsched/exec.c +++ b/usr/src/cmd/lp/cmd/lpsched/exec.c @@ -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 @@ execvpe(char *name, char *const argv[], char *const envp[]) } static char time_buf[50]; + /** ** exec() - FORK AND EXEC CHILD PROCESS **/ @@ -304,6 +309,8 @@ exec(int type, ...) 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 @@ exec(int type, ...) for (i = 0; i < OpenMax; i++) if (i != ChildMd->writefd) Close (i); - setpgrp(); /* Set a default path */ @@ -717,6 +723,14 @@ exec(int type, ...) 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 @@ exec(int type, ...) 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 @@ exec(int type, ...) 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 @@ exec(int type, ...) 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); diff --git a/usr/src/cmd/lp/cmd/lpsched/validate.c b/usr/src/cmd/lp/cmd/lpsched/validate.c index 017dad792d..2791428e06 100644 --- a/usr/src/cmd/lp/cmd/lpsched/validate.c +++ b/usr/src/cmd/lp/cmd/lpsched/validate.c @@ -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_width = 0; 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 @@ _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp, 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 @@ _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp, 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 @@ _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp, 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 @@ _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp, 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 @@ _chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs) char * paper = NULL; char ** pt; + int nobanner_not_allowed = 0; /* @@ -844,11 +909,47 @@ _chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs) 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 @@ free_candidate(CANDIDATE *pc) 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); +} diff --git a/usr/src/cmd/lp/cmd/lpstat/Makefile b/usr/src/cmd/lp/cmd/lpstat/Makefile index 2623a14f3b..9e9b661703 100644 --- a/usr/src/cmd/lp/cmd/lpstat/Makefile +++ b/usr/src/cmd/lp/cmd/lpstat/Makefile @@ -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 @@ LPLIBS = $(LIBACC) \ SYSLIBS= -lcurses -LDLIBS += $(LPLIBS) $(SYSLIBS) $(I18N) +LDLIBS += $(LPLIBS) $(SYSLIBS) $(I18N) -z lazyload -lsecdb -z nolazyload POFILE= lp_cmd_lpstat.po diff --git a/usr/src/cmd/lp/cmd/lpstat/lpstat.h b/usr/src/cmd/lp/cmd/lpstat/lpstat.h index a01ef9708a..b1d9a6d76f 100644 --- a/usr/src/cmd/lp/cmd/lpstat/lpstat.h +++ b/usr/src/cmd/lp/cmd/lpstat/lpstat.h @@ -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_request ( char ** ); 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 *); diff --git a/usr/src/cmd/lp/cmd/lpstat/output.c b/usr/src/cmd/lp/cmd/lpstat/output.c index f03a7ec86d..1cf20519a3 100644 --- a/usr/src/cmd/lp/cmd/lpstat/output.c +++ b/usr/src/cmd/lp/cmd/lpstat/output.c @@ -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 @@ output(int type) char *class, *user, + *slabel, *reject_reason, *request_id, *printer, @@ -131,6 +131,7 @@ output(int type) &status, &request_id, &user, + &slabel, &size, &date, &state, @@ -147,8 +148,9 @@ output(int type) 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 @@ output(int type) &status, &request_id, &user, + &slabel, &size, &date, &state, @@ -178,8 +181,9 @@ output(int type) 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; } diff --git a/usr/src/cmd/lp/cmd/lpstat/request.c b/usr/src/cmd/lp/cmd/lpstat/request.c index 85bd2a64b8..6ced71d4e1 100644 --- a/usr/src/cmd/lp/cmd/lpstat/request.c +++ b/usr/src/cmd/lp/cmd/lpstat/request.c @@ -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 @@ do_user(char **list) 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 @@ putoline(char *request_id, char *user, long size, time_t clock, int state, ((showRank) ? IDSIZE - 2 : IDSIZE), request_id, LOGMAX-1, - user, + user_buf, OSIZE, size, ((showRank) ? "" : " "), date); - if (!(verbosity & (V_LONG|V_BITS))) { /* diff --git a/usr/src/cmd/lp/cmd/lpsystem.c b/usr/src/cmd/lp/cmd/lpsystem.c index b919330137..6819f06248 100644 --- a/usr/src/cmd/lp/cmd/lpsystem.c +++ b/usr/src/cmd/lp/cmd/lpsystem.c @@ -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 @@ static void 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); + } } } /*==================================================================*/ diff --git a/usr/src/cmd/lp/include/lp.h b/usr/src/cmd/lp/include/lp.h index 4a7beb3637..9cc5c011f2 100644 --- a/usr/src/cmd/lp/include/lp.h +++ b/usr/src/cmd/lp/include/lp.h @@ -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 @@ extern int chownmod(char *path, uid_t owner, gid_t group, mode_t mode); 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 diff --git a/usr/src/cmd/lp/include/msgs.h b/usr/src/cmd/lp/include/msgs.h index f9aa711d59..7fa704603e 100644 --- a/usr/src/cmd/lp/include/msgs.h +++ b/usr/src/cmd/lp/include/msgs.h @@ -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 @@ typedef struct 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; diff --git a/usr/src/cmd/lp/include/secure.h b/usr/src/cmd/lp/include/secure.h index b9b6323cea..ee95ff89db 100644 --- a/usr/src/cmd/lp/include/secure.h +++ b/usr/src/cmd/lp/include/secure.h @@ -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 @@ typedef struct SECURE { char *system; char *user; char *req_id; + char *slabel; } SECURE; /** diff --git a/usr/src/cmd/lp/lib/access/allowed.c b/usr/src/cmd/lp/lib/access/allowed.c index a0a5eb7ff1..c8f6844af6 100644 --- a/usr/src/cmd/lp/lib/access/allowed.c +++ b/usr/src/cmd/lp/lib/access/allowed.c @@ -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 ( 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 @@ allowed (item, allow, deny) 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)); +} diff --git a/usr/src/cmd/lp/lib/lp/Makefile b/usr/src/cmd/lp/lib/lp/Makefile index 440d8002da..3d14c214b8 100644 --- a/usr/src/cmd/lp/lib/lp/Makefile +++ b/usr/src/cmd/lp/lib/lp/Makefile @@ -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 @@ OBJECTS = Syscalls.o \ syntax.o \ tidbit.o \ tinames.o \ + tx.o \ wherelist.o \ which.o diff --git a/usr/src/cmd/lp/lib/lp/tx.c b/usr/src/cmd/lp/lib/lp/tx.c new file mode 100644 index 0000000000..5ab2944dc1 --- /dev/null +++ b/usr/src/cmd/lp/lib/lp/tx.c @@ -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); +} diff --git a/usr/src/cmd/lp/lib/msgs/mlisten.c b/usr/src/cmd/lp/lib/msgs/mlisten.c index f6f9c3d5be..b792801ccf 100644 --- a/usr/src/cmd/lp/lib/msgs/mlisten.c +++ b/usr/src/cmd/lp/lib/msgs/mlisten.c @@ -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 @@ mlisten() 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); diff --git a/usr/src/cmd/lp/lib/msgs/msgfmts.c b/usr/src/cmd/lp/lib/msgs/msgfmts.c index 0596079356..efe7bfc9ea 100644 --- a/usr/src/cmd/lp/lib/msgs/msgfmts.c +++ b/usr/src/cmd/lp/lib/msgs/msgfmts.c @@ -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 @@ char *_lp_msg_fmts[] = "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 @@ char *_lp_msg_fmts[] = "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 @@ char *_lp_msg_fmts[] = "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, }; diff --git a/usr/src/cmd/lp/lib/papi/Makefile b/usr/src/cmd/lp/lib/papi/Makefile index b7afa69c33..72c7ff60a5 100644 --- a/usr/src/cmd/lp/lib/papi/Makefile +++ b/usr/src/cmd/lp/lib/papi/Makefile @@ -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. 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 diff --git a/usr/src/cmd/lp/lib/papi/job.c b/usr/src/cmd/lp/lib/papi/job.c index c2c8843690..ff8aea70b7 100644 --- a/usr/src/cmd/lp/lib/papi/job.c +++ b/usr/src/cmd/lp/lib/papi/job.c @@ -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 @@ papiJobQuery(papi_service_t handle, const char *printer, const int32_t job_id, *request_id = NULL, *charset = NULL, *user = NULL, + *slabel = NULL, *file = NULL; time_t date = 0; size_t size = 0; @@ -801,7 +801,7 @@ papiJobQuery(papi_service_t handle, const char *printer, const int32_t job_id, 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 @@ papiJobQuery(papi_service_t handle, const char *printer, const int32_t job_id, 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); diff --git a/usr/src/cmd/lp/lib/papi/lpsched-jobs.c b/usr/src/cmd/lp/lib/papi/lpsched-jobs.c index 190aa9a3bd..225cc08dcf 100644 --- a/usr/src/cmd/lp/lib/papi/lpsched-jobs.c +++ b/usr/src/cmd/lp/lib/papi/lpsched-jobs.c @@ -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 @@ lpsched_request_to_job_attributes(REQUEST *r, job_t *j) * 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 @@ job_status_to_attributes(job_t *job, char *req_id, char *user, size_t size, "lpsched-file", file); addLPString(&job->attributes, PAPI_ATTR_EXCL, "job-name", file); + addLPString(&job->attributes, PAPI_ATTR_EXCL, + "tsol-sensitivity-label", slabel); } void diff --git a/usr/src/cmd/lp/lib/papi/mapfile-vers b/usr/src/cmd/lp/lib/papi/mapfile-vers index 0aaa691f45..2bddef28d0 100644 --- a/usr/src/cmd/lp/lib/papi/mapfile-vers +++ b/usr/src/cmd/lp/lib/papi/mapfile-vers @@ -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 @@ SUNWprivate_1.1 { papiServiceCreate; papiServiceDestroy; + papiServiceSetPeer; # used by to pass peer connection papiServiceSetUserName; papiServiceSetPassword; papiServiceSetEncryption; diff --git a/usr/src/cmd/lp/lib/papi/papi_impl.h b/usr/src/cmd/lp/lib/papi/papi_impl.h index 8dfdb2a1c0..d2359f4e73 100644 --- a/usr/src/cmd/lp/lib/papi/papi_impl.h +++ b/usr/src/cmd/lp/lib/papi/papi_impl.h @@ -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_read_job_configuration(service_t *svc, job_t *j, 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, diff --git a/usr/src/cmd/lp/lib/papi/printer.c b/usr/src/cmd/lp/lib/papi/printer.c index 8a3bd8c63b..2bfc1eabc8 100644 --- a/usr/src/cmd/lp/lib/papi/printer.c +++ b/usr/src/cmd/lp/lib/papi/printer.c @@ -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 @@ papiPrinterListJobs(papi_service_t handle, const char *name, *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 @@ papiPrinterListJobs(papi_service_t handle, const char *name, 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'; diff --git a/usr/src/cmd/lp/lib/papi/service.c b/usr/src/cmd/lp/lib/papi/service.c index 6444bdf06b..d4512636f4 100644 --- a/usr/src/cmd/lp/lib/papi/service.c +++ b/usr/src/cmd/lp/lib/papi/service.c @@ -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 @@ papiServiceDestroy(papi_service_t handle) } } +/* + * 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) { diff --git a/usr/src/cmd/lp/lib/secure/secure.c b/usr/src/cmd/lp/lib/secure/secure.c index 4bc257f2b0..09796dec5e 100644 --- a/usr/src/cmd/lp/lib/secure/secure.c +++ b/usr/src/cmd/lp/lib/secure/secure.c @@ -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 @@ getsecure(char *file) 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 @@ putsecure(char *file, SECURE *secbufp) 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); diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c index 4d72a12b5a..ab0b15c58b 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c +++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c @@ -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 @@ static const mdb_dcmd_t dcmds[] = { /* 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 @@ static const mdb_walker_t walkers[] = { { "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. diff --git a/usr/src/cmd/mdb/common/modules/genunix/net.c b/usr/src/cmd/mdb/common/modules/genunix/net.c index 209b207bd3..0195489ed9 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/net.c +++ b/usr/src/cmd/mdb/common/modules/genunix/net.c @@ -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 @@ netstat_tcp_verbose_header_pr(void) "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 @@ netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 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)) { diff --git a/usr/src/cmd/mdb/common/modules/genunix/tsol.c b/usr/src/cmd/mdb/common/modules/genunix/tsol.c new file mode 100644 index 0000000000..3810738a62 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/tsol.c @@ -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); +} diff --git a/usr/src/cmd/mdb/common/modules/genunix/tsol.h b/usr/src/cmd/mdb/common/modules/genunix/tsol.h new file mode 100644 index 0000000000..abfb626056 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/tsol.h @@ -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 */ diff --git a/usr/src/cmd/mdb/intel/amd64/genunix/Makefile b/usr/src/cmd/mdb/intel/amd64/genunix/Makefile index 25af0c5a02..e199c01aa7 100644 --- a/usr/src/cmd/mdb/intel/amd64/genunix/Makefile +++ b/usr/src/cmd/mdb/intel/amd64/genunix/Makefile @@ -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 @@ COMMONSRCS = \ sysevent.c \ thread.c \ tsd.c \ + tsol.c \ vfs.c \ zone.c diff --git a/usr/src/cmd/mdb/intel/ia32/genunix/Makefile b/usr/src/cmd/mdb/intel/ia32/genunix/Makefile index eec8884381..eb8bea1021 100644 --- a/usr/src/cmd/mdb/intel/ia32/genunix/Makefile +++ b/usr/src/cmd/mdb/intel/ia32/genunix/Makefile @@ -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 @@ COMMONSRCS = \ sysevent.c \ thread.c \ tsd.c \ + tsol.c \ vfs.c \ zone.c diff --git a/usr/src/cmd/mdb/sparc/v9/genunix/Makefile b/usr/src/cmd/mdb/sparc/v9/genunix/Makefile index 460d76057e..266770510f 100644 --- a/usr/src/cmd/mdb/sparc/v9/genunix/Makefile +++ b/usr/src/cmd/mdb/sparc/v9/genunix/Makefile @@ -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 @@ COMMONSRCS = \ sysevent.c \ thread.c \ tsd.c \ + tsol.c \ vfs.c \ zone.c diff --git a/usr/src/cmd/netfiles/nsswitch.dns b/usr/src/cmd/netfiles/nsswitch.dns index 6ee7b1a0eb..c545f0b57b 100644 --- a/usr/src/cmd/netfiles/nsswitch.dns +++ b/usr/src/cmd/netfiles/nsswitch.dns @@ -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 @@ printers: user files auth_attr: files prof_attr: files project: files + +tnrhtp: files +tnrhdb: files diff --git a/usr/src/cmd/netfiles/nsswitch.files b/usr/src/cmd/netfiles/nsswitch.files index cadac05d72..da48bed918 100644 --- a/usr/src/cmd/netfiles/nsswitch.files +++ b/usr/src/cmd/netfiles/nsswitch.files @@ -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 @@ printers: user files auth_attr: files prof_attr: files project: files + +tnrhtp: files +tnrhdb: files diff --git a/usr/src/cmd/netfiles/nsswitch.ldap b/usr/src/cmd/netfiles/nsswitch.ldap index 26edfec601..fb5047291d 100644 --- a/usr/src/cmd/netfiles/nsswitch.ldap +++ b/usr/src/cmd/netfiles/nsswitch.ldap @@ -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 @@ aliases: files ldap # 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 diff --git a/usr/src/cmd/nscd/server.c b/usr/src/cmd/nscd/server.c index 349666a8a6..d4cba76b85 100644 --- a/usr/src/cmd/nscd/server.c +++ b/usr/src/cmd/nscd/server.c @@ -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 @@ main(int argc, char ** argv) 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 @@ main(int argc, char ** argv) /* 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); diff --git a/usr/src/cmd/nscd/svc-nscd b/usr/src/cmd/nscd/svc-nscd index 67af46a86e..a611923be4 100644 --- a/usr/src/cmd/nscd/svc-nscd +++ b/usr/src/cmd/nscd/svc-nscd @@ -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="" diff --git a/usr/src/cmd/praudit/Makefile b/usr/src/cmd/praudit/Makefile index e51e7941a5..1cc2377878 100644 --- a/usr/src/cmd/praudit/Makefile +++ b/usr/src/cmd/praudit/Makefile @@ -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 @@ XGETFLAGS += -a -x praudit.xcl 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: diff --git a/usr/src/cmd/praudit/token.c b/usr/src/cmd/praudit/token.c index 356b29c221..09fdf0d6a2 100644 --- a/usr/src/cmd/praudit/token.c +++ b/usr/src/cmd/praudit/token.c @@ -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 @@ xclient_token(pr_context_t *context) 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 @@ slabel_token(pr_context_t *context) 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 @@ slabel_token(pr_context_t *context) } } return (returnstat); -#else /* !TSOL */ - return (-1); -#endif /* TSOL */ } /* @@ -2280,108 +2273,3 @@ privilege_token(pr_context_t *context) /* 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 */ -} diff --git a/usr/src/cmd/praudit/toktable.c b/usr/src/cmd/praudit/toktable.c index 46081b21fd..dd0f07a9eb 100644 --- a/usr/src/cmd/praudit/toktable.c +++ b/usr/src/cmd/praudit/toktable.c @@ -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 @@ init_tokens(void) 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); diff --git a/usr/src/cmd/praudit/toktable.h b/usr/src/cmd/praudit/toktable.h index 261bf29d01..2764b678da 100644 --- a/usr/src/cmd/praudit/toktable.h +++ b/usr/src/cmd/praudit/toktable.h @@ -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 acl_token(); 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(); diff --git a/usr/src/cmd/print/gateway/adaptor.c b/usr/src/cmd/print/gateway/adaptor.c index ebe6aa97a0..8bb14c148b 100644 --- a/usr/src/cmd/print/gateway/adaptor.c +++ b/usr/src/cmd/print/gateway/adaptor.c @@ -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 @@ adaptor_spooler_accepting_jobs(const char *printer) 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 @@ adaptor_client_access(const char *printer, const char *host) ((fpt = (int (*)())adaptor_function(paradigm_name, "client_access")) != NULL)) return ((int)(fpt)((primary_name ? primary_name : printer), - host)); + host, peerfd)); return (-1); } diff --git a/usr/src/cmd/print/gateway/adaptor.h b/usr/src/cmd/print/gateway/adaptor.h index a717c77ffc..48ebdd6750 100644 --- a/usr/src/cmd/print/gateway/adaptor.h +++ b/usr/src/cmd/print/gateway/adaptor.h @@ -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 "C" { 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, diff --git a/usr/src/cmd/print/gateway/main.c b/usr/src/cmd/print/gateway/main.c index af03c6f067..198447fa2e 100644 --- a/usr/src/cmd/print/gateway/main.c +++ b/usr/src/cmd/print/gateway/main.c @@ -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 @@ remote_host_name(FILE *fp) return (hostname); } - static int request_id_no(const char *filename) { @@ -559,7 +556,7 @@ main(int ac, char *av[]) 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, diff --git a/usr/src/cmd/ptools/ppriv/ppriv.c b/usr/src/cmd/ptools/ppriv/ppriv.c index ba8d7c4edc..596ceed347 100644 --- a/usr/src/cmd/ptools/ppriv/ppriv.c +++ b/usr/src/cmd/ptools/ppriv/ppriv.c @@ -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 exec = B_FALSE; 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ usage(void) { (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 @@ privupdate_self(void) { 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(); diff --git a/usr/src/cmd/rpcbind/bind.xml b/usr/src/cmd/rpcbind/bind.xml index deda9c3211..5ddf2592e4 100644 --- a/usr/src/cmd/rpcbind/bind.xml +++ b/usr/src/cmd/rpcbind/bind.xml @@ -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> diff --git a/usr/src/cmd/rpcbind/rpcbind.c b/usr/src/cmd/rpcbind/rpcbind.c index 9132c7bd7a..4a31ac0283 100644 --- a/usr/src/cmd/rpcbind/rpcbind.c +++ b/usr/src/cmd/rpcbind/rpcbind.c @@ -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 int check_netconfig(void); 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 @@ main(int argc, char *argv[]) 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 @@ main(int argc, char *argv[]) * 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 @@ init_transport(struct netconfig *nconf) 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 @@ init_transport(struct netconfig *nconf) 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 @@ parseargs(int argc, char *argv[]) } 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 @@ setopt_reuseaddr(int fd) } 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; diff --git a/usr/src/cmd/smserverd/myaudit.c b/usr/src/cmd/smserverd/myaudit.c index 38f7296cfb..8df45e745f 100644 --- a/usr/src/cmd/smserverd/myaudit.c +++ b/usr/src/cmd/smserverd/myaudit.c @@ -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 @@ audit_audit(door_data_t *door_dp) (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)); } diff --git a/usr/src/cmd/svc/shell/smf_include.sh b/usr/src/cmd/svc/shell/smf_include.sh index 5376d381bf..066993fe01 100644 --- a/usr/src/cmd/svc/shell/smf_include.sh +++ b/usr/src/cmd/svc/shell/smf_include.sh @@ -74,6 +74,17 @@ smf_is_nonglobalzone() { 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) # diff --git a/usr/src/cmd/tar/Makefile b/usr/src/cmd/tar/Makefile index 03d0abbd72..2172afa2ac 100644 --- a/usr/src/cmd/tar/Makefile +++ b/usr/src/cmd/tar/Makefile @@ -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 @@ include ../Makefile.cmd 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) diff --git a/usr/src/cmd/tar/tar.c b/usr/src/cmd/tar/tar.c index 92eb40a452..c35cc61cb0 100644 --- a/usr/src/cmd/tar/tar.c +++ b/usr/src/cmd/tar/tar.c @@ -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 @@ extern int defcntl(); #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 @@ struct sec_attr { char attr_info[1]; } *attr; -#define ACL_HDR 'A' - /* * * Tar has been changed to support extended attributes. @@ -382,7 +384,7 @@ struct file_list { 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 char *getgroup(gid_t); 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_extra_attributes(char *longname, char *shortname, 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 Pflag; /* POSIX conformant archive */ 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 @@ main(int argc, char *argv[]) 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 @@ main(int argc, char *argv[]) "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 @@ usage(void) 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 @@ usage(void) { (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 @@ doxtract(char *argv[]) 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 @@ doxtract(char *argv[]) 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 @@ doxtract(char *argv[]) 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 @@ doxtract(char *argv[]) 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 @@ doxtract(char *argv[]) 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 @@ filedone: 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 @@ filedone: } 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 @@ filedone: } 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 @@ filedone: 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 @@ int 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); + if (attr_type != DIR_TYPE) { + if (attrtext == NULL) + return (0); + } - switch (acl_type(aclp)) { - case ACLENT_T: - case ACE_T: - attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT); + switch (attr_type) { + case UFSD_ACL: + case ACE_ACL: if (attrtext == NULL) { (void) fprintf(stderr, "acltotext failed\n"); return (-1); @@ -5582,15 +5703,28 @@ append_secattr( (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 @@ append_secattr( if (new_secinfo == NULL) { (void) fprintf(stderr, "can't allocate memory\n"); *secinfo_len -= newattrsize; + free(attr); return (-1); } @@ -5611,6 +5746,7 @@ append_secattr( (void) memcpy(new_secinfo + oldsize, attr, newattrsize); free(*secinfo); + free(attr); *secinfo = new_secinfo; return (0); } @@ -6779,7 +6915,17 @@ put_extra_attributes(char *longname, char *shortname, char *prefix, /* 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 @@ chop_endslashes(char *path) } } } +/* 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, ¤tlabel) != 0) { + (void) fprintf(stderr, + gettext("tar: can't get label for " + " %s, getlabel() error: %s\n"), + filename, strerror(errno)); + return (0); + } else if ((blequal(¤tlabel, &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 */ diff --git a/usr/src/cmd/truss/Makefile.com b/usr/src/cmd/truss/Makefile.com index bcb8a69882..b849ad1866 100644 --- a/usr/src/cmd/truss/Makefile.com +++ b/usr/src/cmd/truss/Makefile.com @@ -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 @@ include ../../Makefile.cmd 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 diff --git a/usr/src/cmd/truss/expound.c b/usr/src/cmd/truss/expound.c index 9269fd7ed1..cb64154f41 100644 --- a/usr/src/cmd/truss/expound.c +++ b/usr/src/cmd/truss/expound.c @@ -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 @@ show_zone_create_args(private_t *pri, long offset) (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 @@ show_zone_create_args32(private_t *pri, long offset) (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); } diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c index 2f017e6018..7ab35fd3b5 100644 --- a/usr/src/cmd/truss/print.c +++ b/usr/src/cmd/truss/print.c @@ -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 @@ prt_zga(private_t *pri, int raw, long val) 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 @@ prt_atc(private_t *pri, int raw, long val) } /* + * 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 @@ void (* const Print[])() = { 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 */ }; diff --git a/usr/src/cmd/truss/print.h b/usr/src/cmd/truss/print.h index 337b26f6c1..7714525875 100644 --- a/usr/src/cmd/truss/print.h +++ b/usr/src/cmd/truss/print.h @@ -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 @@ extern "C" { #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 */ /* diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c index 30a681c7f4..d6779c63d7 100644 --- a/usr/src/cmd/truss/systable.c +++ b/usr/src/cmd/truss/systable.c @@ -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 @@ const struct systable systable[] = { {"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 @@ static const struct systable zonetable[] = { }; #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 @@ const struct sysalias sysalias[] = { { "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 @@ subsys(int syscall, int subcode) 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 @@ getsubcode(private_t *pri) 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 @@ maxsyscalls() + NPRIVSYSCODE - 1 + NUCREDSYSCODE - 1 + NPORTCODE - 1 - + NZONECODE - 1); + + NZONECODE - 1 + + NLABELCODE - 1); } /* @@ -1341,6 +1362,8 @@ nsubcodes(int syscall) return (NPORTCODE); case SYS_zone: /* zone */ return (NZONECODE); + case SYS_labelsys: + return (NLABELCODE); default: return (1); } diff --git a/usr/src/cmd/volmgt/rmm/Makefile b/usr/src/cmd/volmgt/rmm/Makefile index 0f9dba5b2b..9c6390e1ba 100644 --- a/usr/src/cmd/volmgt/rmm/Makefile +++ b/usr/src/cmd/volmgt/rmm/Makefile @@ -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 @@ CFLAGS += $(CCVERBOSE) -D_FILE_OFFSET_BITS=64 CPPFLAGS += -DACT_VERS=${ACT_VERS} -DIDENT_VERS=${IDENT_VERS} -$(PROG) := LDLIBS += -lvolmgt -ladm +$(PROG) := LDLIBS += -lvolmgt -ladm -lcontract $(ACTSVOL) := LDLIBS += -lvolmgt $(ACTS) := LDLIBS += -lc diff --git a/usr/src/cmd/volmgt/rmm/rmm.c b/usr/src/cmd/volmgt/rmm/rmm.c index e94a8e0511..630392553e 100644 --- a/usr/src/cmd/volmgt/rmm/rmm.c +++ b/usr/src/cmd/volmgt/rmm/rmm.c @@ -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 @@ struct action_list ** action_list = NULL; 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) 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 @@ main(int argc, char **argv) } 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 @@ exec_actions(struct action_arg **aa, bool_t premount) 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 @@ exec_mounts(struct action_arg **aa) if (aa[ai]->aa_mountpoint) mnt_ai = ai; } - if (ma[CMD_SHARE] != NULL) { /* * export the file system. @@ -904,10 +1030,17 @@ exec_mounts(struct action_arg **aa) (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 @@ exec_umounts(struct action_arg **aa) dprintf("%s[%d]: mount path = %s\n", __FILE__, __LINE__, mnt_path); - - if ((mountpoint = getmntpoint(mnt_path)) == NULL) { + if ((mountpoint = getmntpoint(mnt_path)) == NULL) continue; - } + /* * find the right mount arguments for this device */ @@ -1006,7 +1138,6 @@ exec_umounts(struct action_arg **aa) if (ma != NULL) { unshare_mount(aa[ai], ma); } - /* * do the actual umount */ @@ -1020,13 +1151,11 @@ exec_umounts(struct action_arg **aa) } /* 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 @@ exec_umounts(struct action_arg **aa) * 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 @@ hard_mount(struct action_arg *aa, struct mount_args *ma, bool_t *rdonly) */ 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 @@ hard_mount(struct action_arg *aa, struct mount_args *ma, bool_t *rdonly) 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: malloc failed\n"), + gettext("%s(%ld) error: path too long\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) { + 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", aa->aa_media, targ_dir); } + zonemountpoint = mountpoint + strlen(mnt_zoneroot); + /* make our mountpoint */ (void) makepath(mountpoint, 0755); @@ -1455,7 +1629,7 @@ hard_mount(struct action_arg *aa, struct mount_args *ma, bool_t *rdonly) 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 @@ hard_mount(struct action_arg *aa, struct mount_args *ma, bool_t *rdonly) (void) rmdir(mountpoint); /* cleanup */ ret_val = FALSE; } - if (mountpoint != NULL) - free(mountpoint); - return (ret_val); } diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c index 8e5bb30a32..ff2be8ffaf 100644 --- a/usr/src/cmd/zoneadm/zoneadm.c +++ b/usr/src/cmd/zoneadm/zoneadm.c @@ -398,7 +398,7 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) 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 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) 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); + /* + * 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)); } - (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 @@ fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr) */ 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 @@ list_func(int argc, char *argv[]) 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 @@ unconfigure_zone(char *zonepath) } /* + * 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. */ diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile index 3ce403a243..33c89cd085 100644 --- a/usr/src/cmd/zoneadmd/Makefile +++ b/usr/src/cmd/zoneadmd/Makefile @@ -17,6 +17,8 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + + # # @@ -38,8 +40,10 @@ POFILE=zoneadmd_all.po 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: diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c index 342f66d6bf..13a5507fde 100644 --- a/usr/src/cmd/zoneadmd/vplat.c +++ b/usr/src/cmd/zoneadmd/vplat.c @@ -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 @@ static char kernzone[ZONENAME_MAX]; /* 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 @@ make_one_dir(zlog_t *zlogp, const char *prefix, const char *subdir, mode_t mode) * 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 @@ unmount_filesystems(zlog_t *zlogp, zoneid_t zoneid, boolean_t unmount_cmd) (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 @@ check_path(zlog_t *zlogp, const char *path) 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 @@ mount_filesystems(zlog_t *zlogp, boolean_t mount_cmd) 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 @@ bind_to_pool(zlog_t *zlogp, zoneid_t zoneid) 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 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd) 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 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd) 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 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd) 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 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd) 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 @@ error: if (fp != NULL) zonecfg_close_scratch(fp); lofs_discard_mnttab(); + if (zcent != NULL) + tsol_freezcent(zcent); return (rval); } @@ -3109,6 +3683,8 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd) goto error; } + remove_mlps(zlogp, zoneid); + if (zone_destroy(zoneid) != 0) { zerror(zlogp, B_TRUE, "unable to destroy zone"); goto error; diff --git a/usr/src/common/ipf/ip_compat.h b/usr/src/common/ipf/ip_compat.h index f87a7c2d9b..56262aff10 100644 --- a/usr/src/common/ipf/ip_compat.h +++ b/usr/src/common/ipf/ip_compat.h @@ -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 @@ typedef struct tcpiphdr tcpiphdr_t; #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 diff --git a/usr/src/common/tsol/blabel.c b/usr/src/common/tsol/blabel.c new file mode 100644 index 0000000000..f99535c9ee --- /dev/null +++ b/usr/src/common/tsol/blabel.c @@ -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); +} diff --git a/usr/src/head/auth_list.h b/usr/src/head/auth_list.h index 4bf9c17511..d0d625bc72 100644 --- a/usr/src/head/auth_list.h +++ b/usr/src/head/auth_list.h @@ -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 @@ extern "C" { #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 diff --git a/usr/src/head/nss_dbdefs.h b/usr/src/head/nss_dbdefs.h index a427674214..dc37584a46 100644 --- a/usr/src/head/nss_dbdefs.h +++ b/usr/src/head/nss_dbdefs.h @@ -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 @@ extern "C" { #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 @@ extern "C" { #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 @@ extern "C" { #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 @@ extern "C" { #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 @@ extern "C" { #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 @@ extern char **_nss_netdb_aliases(); #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. diff --git a/usr/src/head/protocols/routed.h b/usr/src/head/protocols/routed.h index d4ca467878..db58d9a406 100644 --- a/usr/src/head/protocols/routed.h +++ b/usr/src/head/protocols/routed.h @@ -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 @@ struct netauth { } 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 rip { 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 @@ struct entryinfo { #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 */ diff --git a/usr/src/head/tar.h b/usr/src/head/tar.h index d3dcd35ab6..0510bd7a68 100644 --- a/usr/src/head/tar.h +++ b/usr/src/head/tar.h @@ -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 @@ extern "C" { #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 diff --git a/usr/src/head/ucred.h b/usr/src/head/ucred.h index a0d4af444a..e10ab26f52 100644 --- a/usr/src/head/ucred.h +++ b/usr/src/head/ucred.h @@ -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 int getpeerucred(int, ucred_t **); 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 int getpeerucred(/* int, ucred_t ** */); extern zoneid_t ucred_getzoneid(/* ucred_t * */); +extern bslabel_t *ucred_getlabel(/* const ucred_t * */); + extern projid_t ucred_getprojid(/* ucred_t * */); #endif /* __STDC__ */ diff --git a/usr/src/head/user_attr.h b/usr/src/head/user_attr.h index 2f79d937fd..e5e6c9329c 100644 --- a/usr/src/head/user_attr.h +++ b/usr/src/head/user_attr.h @@ -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 @@ struct __FILE; /* structure tag for type FILE defined in stdio.h */ #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 /* diff --git a/usr/src/head/zone.h b/usr/src/head/zone.h index 407cf5f809..c950ee5aa6 100644 --- a/usr/src/head/zone.h +++ b/usr/src/head/zone.h @@ -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 @@ extern int zone_get_id(const char *, zoneid_t *); /* 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); diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 892a841235..c7d90d71de 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -184,6 +184,8 @@ SUBDIRS += \ libxnet \ libzonecfg \ libzoneinfo \ + libtsnet \ + libtsol \ gss_mechs/mech_spnego \ gss_mechs/mech_dummy \ gss_mechs/mech_dh \ @@ -268,6 +270,7 @@ MSGSUBDIRS= \ libsldap \ libslp \ libsmedia \ + libtsol \ libuutil \ libwanboot \ libwanbootutil \ @@ -327,6 +330,7 @@ HDRSUBDIRS= libaio \ libmail \ libmtmalloc \ libnvpair \ + libnsl \ libpam \ libpctx \ libpicl \ @@ -349,6 +353,8 @@ HDRSUBDIRS= libaio \ libtnf \ libtnfctl \ libtnfprobe \ + libtsnet \ + libtsol \ libvolmgt \ libumem \ libuutil \ @@ -425,6 +431,7 @@ auditd_plugins: libbsm libnsl libsecdb 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 @@ sasl_plugins: pkcs11 libgss libsocket libsasl 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 diff --git a/usr/src/lib/auditd_plugins/syslog/systoken.c b/usr/src/lib/auditd_plugins/syslog/systoken.c index 7ccc79d3c9..ae251a67bd 100644 --- a/usr/src/lib/auditd_plugins/syslog/systoken.c +++ b/usr/src/lib/auditd_plugins/syslog/systoken.c @@ -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 @@ xclient_token(parse_context_t *ctx) 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 @@ privilege_token(parse_context_t *ctx) /* * 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 */ } /* diff --git a/usr/src/lib/auditd_plugins/syslog/systoken.h b/usr/src/lib/auditd_plugins/syslog/systoken.h index db60ae43aa..af6517845a 100644 --- a/usr/src/lib/auditd_plugins/syslog/systoken.h +++ b/usr/src/lib/auditd_plugins/syslog/systoken.h @@ -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 acl_token(adr_t *, parse_context_t *); 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 *); diff --git a/usr/src/lib/common/inc/c_synonyms.h b/usr/src/lib/common/inc/c_synonyms.h index 06fa420471..2143bb8d06 100644 --- a/usr/src/lib/common/inc/c_synonyms.h +++ b/usr/src/lib/common/inc/c_synonyms.h @@ -414,6 +414,7 @@ extern "C" { #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 diff --git a/usr/src/lib/libbsm/Makefile b/usr/src/lib/libbsm/Makefile index 55ccf943e2..4cc23687a8 100644 --- a/usr/src/lib/libbsm/Makefile +++ b/usr/src/lib/libbsm/Makefile @@ -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 @@ package := TARGET= package 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 @@ ARSYMLNK=$(RESAL)/files # # 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): $(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 @@ adt_xlate.po: $(COMMONDIR)/adt_xlate.c $(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 diff --git a/usr/src/lib/libbsm/Makefile.com b/usr/src/lib/libbsm/Makefile.com index 3a7318aa72..52871561fc 100644 --- a/usr/src/lib/libbsm/Makefile.com +++ b/usr/src/lib/libbsm/Makefile.com @@ -24,7 +24,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# lib/libbsm/Makefile +# lib/libbsm/Makefile.com # LIBRARY = libbsm.a @@ -67,7 +67,10 @@ OBJECTS= adr.o \ getacval.o \ getauditflags.o \ getdaent.o \ + getdevicerange.o \ getdment.o \ + getdadefs.o \ + devalloc.o \ getfaudflgs.o # @@ -94,7 +97,10 @@ CLOBBERFILES += $(MAPFILE) 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 diff --git a/usr/src/lib/libbsm/audit_class.txt b/usr/src/lib/libbsm/audit_class.txt index 5d0b8c7e03..69b06f2b80 100644 --- a/usr/src/lib/libbsm/audit_class.txt +++ b/usr/src/lib/libbsm/audit_class.txt @@ -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 diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt index 5bcc228838..7403d16365 100644 --- a/usr/src/lib/libbsm/audit_event.txt +++ b/usr/src/lib/libbsm/audit_event.txt @@ -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 diff --git a/usr/src/lib/libbsm/common/adt_token.c b/usr/src/lib/libbsm/common/adt_token.c index 49720539c7..1c6aec718b 100644 --- a/usr/src/lib/libbsm/common/adt_token.c +++ b/usr/src/lib/libbsm/common/adt_token.c @@ -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 @@ adt_to_subject(datadef *def, void *p_data, int required, au_to_newgroups(0, grouplist)); } } + + if (is_system_labeled()) + (void) au_write(event->ae_event_handle, au_to_mylabel()); } /* diff --git a/usr/src/lib/libbsm/common/au_to.c b/usr/src/lib/libbsm/common/au_to.c index 8c8fe49820..3747994d76 100644 --- a/usr/src/lib/libbsm/common/au_to.c +++ b/usr/src/lib/libbsm/common/au_to.c @@ -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_xselect(char *pstring, char *type, short dlen, char *data) } /* + * 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. diff --git a/usr/src/lib/libbsm/common/audit_allocate.c b/usr/src/lib/libbsm/common/audit_allocate.c index e5d8e04d8a..35af6d9b53 100644 --- a/usr/src/lib/libbsm/common/audit_allocate.c +++ b/usr/src/lib/libbsm/common/audit_allocate.c @@ -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 @@ audit_allocate_record(status) } (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)); diff --git a/usr/src/lib/libbsm/common/audit_ftpd.c b/usr/src/lib/libbsm/common/audit_ftpd.c index fb04a40579..023e78cb33 100644 --- a/usr/src/lib/libbsm/common/audit_ftpd.c +++ b/usr/src/lib/libbsm/common/audit_ftpd.c @@ -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 @@ generate_record( (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 @@ audit_ftpd_logout(void) (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 diff --git a/usr/src/lib/libbsm/common/audit_rexd.c b/usr/src/lib/libbsm/common/audit_rexd.c index a868c17909..5c48b810b6 100644 --- a/usr/src/lib/libbsm/common/audit_rexd.c +++ b/usr/src/lib/libbsm/common/audit_rexd.c @@ -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 @@ audit_rexd_fail(msg, hostname, user, uid, gid, shell, cmd) (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 @@ char **cmd; /* argv to be executed locally, may be NULL */ (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 */ diff --git a/usr/src/lib/libbsm/common/audit_rexecd.c b/usr/src/lib/libbsm/common/audit_rexecd.c index 79e33ce765..bb32ed9643 100644 --- a/usr/src/lib/libbsm/common/audit_rexecd.c +++ b/usr/src/lib/libbsm/common/audit_rexecd.c @@ -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 @@ char *cmdbuf; /* command line to be executed locally */ /* 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 @@ char *cmdbuf; /* command line to be executed locally */ /* 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, diff --git a/usr/src/lib/libbsm/common/audit_rshd.c b/usr/src/lib/libbsm/common/audit_rshd.c index f06ba169c7..7ff2523355 100644 --- a/usr/src/lib/libbsm/common/audit_rshd.c +++ b/usr/src/lib/libbsm/common/audit_rshd.c @@ -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 @@ generate_record(char *remuser, /* username at machine requesting service */ (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; diff --git a/usr/src/lib/libbsm/common/devalloc.c b/usr/src/lib/libbsm/common/devalloc.c new file mode 100644 index 0000000000..4541191349 --- /dev/null +++ b/usr/src/lib/libbsm/common/devalloc.c @@ -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); + } +} diff --git a/usr/src/lib/libbsm/common/devalloc.h b/usr/src/lib/libbsm/common/devalloc.h new file mode 100644 index 0000000000..7952a302f5 --- /dev/null +++ b/usr/src/lib/libbsm/common/devalloc.h @@ -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 */ diff --git a/usr/src/lib/libbsm/common/devices.h b/usr/src/lib/libbsm/common/devices.h index 609a0aeb1a..04a3edceea 100644 --- a/usr/src/lib/libbsm/common/devices.h +++ b/usr/src/lib/libbsm/common/devices.h @@ -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; -} devmap_t; +#include <stdio.h> +#include <secdb.h> + +/* + * These are unsupported, SUN-private interfaces. + */ -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 *); +#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 { /* see getdaent(3) */ - char *da_devname; - char *da_devtype; - char *da_devmin; - char *da_devmax; - char *da_devauth; - char *da_devexec; +typedef struct { + char *da_devname; + char *da_devtype; + char *da_devauth; + char *da_devexec; + kva_t *da_devopts; } 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 *); +typedef struct { + char *dmap_devname; + char *dmap_devtype; + char *dmap_devlist; + char **dmap_devarray; +} devmap_t; + +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 *); + +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 } diff --git a/usr/src/lib/libbsm/common/generic.c b/usr/src/lib/libbsm/common/generic.c index 457b2e8c37..d5953826b9 100644 --- a/usr/src/lib/libbsm/common/generic.c +++ b/usr/src/lib/libbsm/common/generic.c @@ -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 @@ aug_audit(void) (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)); } diff --git a/usr/src/lib/libbsm/common/getdadefs.c b/usr/src/lib/libbsm/common/getdadefs.c new file mode 100644 index 0000000000..3f62566293 --- /dev/null +++ b/usr/src/lib/libbsm/common/getdadefs.c @@ -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); +} diff --git a/usr/src/lib/libbsm/common/getdaent.c b/usr/src/lib/libbsm/common/getdaent.c index f461015dbc..2deb5a65d6 100644 --- a/usr/src/lib/libbsm/common/getdaent.c +++ b/usr/src/lib/libbsm/common/getdaent.c @@ -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> +#ifndef lint +static char sccsid[] = "%Z%%M% %I% %E% SMI"; +#endif + +#include <ctype.h> #include <string.h> -#include <malloc.h> +#include <stdlib.h> +#include <tsol/label.h> #include <bsm/devices.h> +#include <bsm/devalloc.h> -#define MAXINT 0x7fffffff; -#ifdef SunOS_CMW -extern char *calloc(); -#endif +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'; -/* - * 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); + return (cnt); } - /* - * _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; -{ - 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); -} - -char * -getdadfield(ptr) -char *ptr; -{ - static char *tptr; - if (ptr != NULL) { - ptr = trim_white(ptr); - } else { - ptr = tptr; - } - if (ptr == NULL) - return (NULL); - tptr = dadskip(ptr); - if (ptr == NULL) - return (NULL); - if (*ptr == NULL) - return (NULL); - return (ptr); -} - /* - * 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. + * _daalloc - + * allocates common buffers and structures. + * returns pointer to the new structure, else returns NULL on error. */ -#ifdef NOTDEF -devalloc_t * -getdadev(name) - register char *name; +static struct _dabuff * +_daalloc(void) { - register struct _dabuff *_da = _daalloc(); - devalloc_t *da; - char line[BUFSIZ + 1]; + struct _dabuff *_da = __dabuff; - 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); - } + 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(); } - enddaent(); - return ((devalloc_t *)NULL); -} - -#endif /* NOTDEF */ + return (__dabuff); +} /* - * 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. + * getdadmfield - + * gets individual fields separated by skip in ptr. */ -devalloc_t * -getdanam(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, (int)sizeof (line), daf) != 0) { - if ((da = interpret(line)) == NULL) - continue; - if (matchname(&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)); +} /* - * 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 @@ enddaent() } } - /* - * 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) - return (0); - if (daf == NULL && (daf = fopen(DEVALLOC, "r")) == NULL) { + if ((_da == 0) || (daf == 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) { + if ((name == NULL) || (_da == 0) || (daf == NULL)) return (NULL); + + 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); } - if (getdaline(line1, (int)sizeof (line1), daf) == 0) - return (NULL); - if ((da = interpret(line1)) == NULL) - return (NULL); - return (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; - - charcnt = strlen(dev); - if (_da == 0) - return (0); - if (da->da_devlist == 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) + char line1[DA_BUFSIZE + 1]; + devalloc_t *da; + struct _dabuff *_da = _daalloc(); + + if ((type == NULL) || (_da == NULL) || (daf == NULL)) + return (NULL); + + while (getdadmline(line1, (int)sizeof (line1), daf) != 0) { + if (strstr(line1, type) == NULL) + continue; + if ((da = da_interpret(line1)) == NULL) continue; - if (strcmp(cp, dev) == 0) - return (1); + if (da_matchtype(da, type)) + return (da); + freedaent(da); } - return (0); + + return (NULL); } -#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. + * da_matchname - + * checks if the specified devalloc_t is for the device specified. + * returns 1 if it is, else returns 0. */ -static int -matchname(dap, name) - devalloc_t **dap; - char *name; +int +da_matchname(devalloc_t *dap, char *name) { - register struct _dabuff *_da = _daalloc(); - devalloc_t *da = *dap; - - if (_da == 0) - return (0); - if (da->da_devname == NULL) + if (dap->da_devname == NULL) return (0); - if (strlen(da->da_devname) != strlen(name)) + + 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); - if (strcmp(da->da_devname, name) == 0) - return (1); - return (0); + + 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); +} /* - * 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 == 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 (_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 (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); } diff --git a/usr/src/lib/libbsm/common/getdevicerange.c b/usr/src/lib/libbsm/common/getdevicerange.c new file mode 100644 index 0000000000..6b993de18f --- /dev/null +++ b/usr/src/lib/libbsm/common/getdevicerange.c @@ -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); +} diff --git a/usr/src/lib/libbsm/common/getdment.c b/usr/src/lib/libbsm/common/getdment.c index 9e4556c9c7..2b13f5bc6e 100644 --- a/usr/src/lib/libbsm/common/getdment.c +++ b/usr/src/lib/libbsm/common/getdment.c @@ -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,446 +19,486 @@ * 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> -#define MAXINT 0x7fffffff; +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 *); 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 *); + + /* - * 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. + * _dmapalloc - + * allocates common buffers and structures. + * returns pointer to the new structure, else returns NULL on error. */ -static char * -trim_white(char *ptr) +static struct _dmapbuff * +_dmapalloc(void) { - 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--; - } + 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; } - if (*ptr == NULL) - return (NULL); - return (ptr); + + return (_dmap); } + /* - * scan string pointed to by pointer "p" - * find next colin or end of line. Null it and - * return pointer to next char. + * setdmapent - + * rewinds the device_maps file to the beginning. */ -static char * -dmapskip(register char *p) +void +setdmapent(void) { - while (*p && *p != ':' && *p != '\n') - ++p; - if (*p == '\n') - *p = '\0'; - else if (*p != '\0') - *p++ = '\0'; - return (p); + struct _dmapbuff *_dmap = _dmapalloc(); + + if (_dmap == NULL) + return; + if (dmapf == NULL) + dmapf = fopen(DEVMAPS_FILE, "r"); + else + rewind(dmapf); } + /* - * scan string pointed to by pointer "p" - * find next colin or end of line. Null it and - * return pointer to next char. + * enddmapent - + * closes device_maps file. */ -static char * -dmapdskip(register char *p) +void +enddmapent(void) { - while (*p && *p != ' ' && *p != '\n') - ++p; - if (*p != '\0') - *p++ = '\0'; - return (p); + struct _dmapbuff *_dmap = _dmapalloc(); + + if (_dmap == NULL) + return; + if (dmapf != NULL) { + (void) fclose(dmapf); + dmapf = NULL; + } } -/* - * _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) +void +freedmapent(devmap_t *dmap) { - 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; + char **darp; + + if ((darp = dmap->dmap_devarray) != NULL) { + while (*darp != NULL) + free(*darp++); + free(dmap->dmap_devarray); + dmap->dmap_devarray = NULL; } - 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 + * 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. */ -static int -getdmapline(char *buff, int len, FILE *stream) +void +setdmapfile(char *file) { - 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); + struct _dmapbuff *_dmap = _dmapalloc(); + + if (_dmap == NULL) + return; + if (dmapf != NULL) { + (void) fclose(dmapf); + dmapf = NULL; + } + DEVMAPS_FILE = file; } -char -*getdmapfield(char *ptr) + +/* + * 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) { - static char *tptr; - if (ptr == NULL) - ptr = tptr; - if (ptr == NULL) - return (NULL); - tptr = dmapskip(ptr); - ptr = trim_white(ptr); - if (ptr == NULL) - return (NULL); - if (*ptr == NULL) + devmap_t *dmap; + struct _dmapbuff *_dmap = _dmapalloc(); + + if ((_dmap == 0) || (dmapf == NULL)) return (NULL); - return (ptr); -} -char -*getdmapdfield(char *ptr) -{ - static char *tptr; - if (ptr != NULL) { - ptr = trim_white(ptr); - } else { - ptr = tptr; + + while (getdadmline(interpdmline, (int)sizeof (interpdmline), + dmapf) != 0) { + if ((dmap = dmap_interpret(interpdmline, + &interpdevmap)) == NULL) + continue; + return (dmap); } - if (ptr == NULL) - return (NULL); - tptr = dmapdskip(ptr); - if (ptr == NULL) - return (NULL); - if (*ptr == NULL) - return (NULL); - return (ptr); + + return (NULL); } + /* - * 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. + * 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 * -getdmapdev(register char *name) +getdmapnam(char *name) { - register struct _dmapbuff *_dmap = _dmapalloc(); - devmap_t *dmap; - char line[BUFSIZ + 1]; + devmap_t *dmap; + struct _dmapbuff *_dmap = _dmapalloc(); - if (_dmap == 0) - return (0); - setdmapent(); - if (!dmapf) + if ((name == NULL) || (_dmap == 0) || (dmapf == NULL)) return (NULL); - while (getdmapline(line, (int)sizeof (line), dmapf) != 0) { - if ((dmap = interpret(line)) == NULL) + + while (getdadmline(interpdmline, (int)sizeof (interpdmline), + dmapf) != 0) { + if (strstr(interpdmline, name) == NULL) continue; - if (matchdev(&dmap, name)) { + 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); } - 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. + * 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 * -getdmapnam(register char *name) +getdmapdev(char *dev) { - register struct _dmapbuff *_dmap = _dmapalloc(); - devmap_t *dmap; - char line[BUFSIZ + 1]; + devmap_t *dmap; + struct _dmapbuff *_dmap = _dmapalloc(); - if (_dmap == 0) - return (0); - setdmapent(); - if (!dmapf) + if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL)) return (NULL); - while (getdmapline(line, (int)sizeof (line), dmapf) != 0) { - if ((dmap = interpret(line)) == NULL) + + while (getdadmline(interpdmline, (int)sizeof (interpdmline), + dmapf) != 0) { + if ((dmap = dmap_interpret(interpdmline, + &interpdevmap)) == NULL) continue; - if (matchname(&dmap, name)) { + if (dmap_matchdev(dmap, dev)) { enddmapent(); return (dmap); } + freedmapent(dmap); } - enddmapent(); + return (NULL); } /* - * setdmapent() essentially rewinds the device_maps file to the begining. + * 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. */ - -void -setdmapent(void) +devmap_t * +getdmaptype(char *type) { - register struct _dmapbuff *_dmap = _dmapalloc(); + devmap_t *dmap; + struct _dmapbuff *_dmap = _dmapalloc(); + if ((type == NULL) || (_dmap == 0) || (dmapf == NULL)) + return (NULL); - if (_dmap == 0) - return; + 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); + } - if (dmapf == NULL) { - dmapf = fopen(DEVMAP, "r"); - } else - rewind(dmapf); + return (NULL); } - /* - * enddmapent() may be called to close the device_maps file when processing - * is complete. + * dmap_matchdev - + * checks if the specified devmap_t is for the device specified. + * returns 1 if it is, else returns 0. */ - -void -enddmapent(void) +int +dmap_matchdev(devmap_t *dmap, char *dev) { - register struct _dmapbuff *_dmap = _dmapalloc(); + char **dva; + char *dv; - if (_dmap == 0) - return; - if (dmapf != NULL) { - (void) fclose(dmapf); - dmapf = NULL; + 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); +} /* - * 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. + * dmap_matchtype - + * checks if the specified devmap_t is for the device specified. + * returns 1 if it is, else returns 0. */ -void -setdmapfile(char *file) +int +dmap_matchtype(devmap_t *dmap, char *type) { - register struct _dmapbuff *_dmap = _dmapalloc(); + if ((dmap->dmap_devtype == NULL) || (type == NULL)) + return (0); - if (_dmap == 0) - return; - if (dmapf != NULL) { - (void) fclose(dmapf); - dmapf = NULL; - } - DEVMAP = file; + return ((strcmp(dmap->dmap_devtype, type) == 0)); } + /* - * 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. + * dmap_matchname - + * checks if the specified devmap_t is for the device specified. + * returns 1 if it is, else returns 0. */ -devmap_t * -getdmaptype(char *tp) +int +dmap_matchname(devmap_t *dmap, char *name) { - register struct _dmapbuff *_dmap = _dmapalloc(); - char line1[BUFSIZ + 1]; - devmap_t *dmap; - - if (_dmap == 0) + if (dmap->dmap_devname == NULL) 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); + return ((strcmp(dmap->dmap_devname, name) == 0)); } /* - * 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. + * dm_match - + * calls dmap_matchname or dmap_matchtype as appropriate. */ -devmap_t * -getdmapent(void) +int +dm_match(devmap_t *dmap, da_args *dargs) { - register struct _dmapbuff *_dmap = _dmapalloc(); - char line1[BUFSIZ + 1]; - devmap_t *dmap; + if (dargs->devinfo->devname) + return (dmap_matchname(dmap, dargs->devinfo->devname)); + else if (dargs->devinfo->devtype) + return (dmap_matchtype(dmap, dargs->devinfo->devtype)); - if (_dmap == 0) - return (0); - if (dmapf == NULL && (dmapf = fopen(DEVMAP, "r")) == NULL) { - return (NULL); - } - if (getdmapline(line1, (int)sizeof (line1), dmapf) == 0) + 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); - if ((dmap = interpret(line1)) == 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 (dmap); + + return (dm); } + /* - * 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. + * dmap_dlexpand - + * expands dmap_devlist of the form `devlist_generate` + * returns unexpanded form if there is no '\`' or in case of error. */ -static int -matchdev(devmap_t **dmapp, char *dev) +static devmap_t * +dmap_dlexpand(devmap_t *dmp) { - 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); + 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'; } - return (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); } + /* - * 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. + * dmapskip - + * scans input string to find next colon or end of line. + * returns pointer to next char. */ -static int -matchname(devmap_t **dmapp, char *name) +static char * +dmapskip(char *p) { - register struct _dmapbuff *_dmap = _dmapalloc(); - devmap_t *dmap = *dmapp; + while (*p && *p != ':' && *p != '\n') + ++p; + if (*p == '\n') + *p = '\0'; + else if (*p != '\0') + *p++ = '\0'; - 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); + return (p); } + /* - * 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. + * dmapdskip - + * scans input string to find next space or end of line. + * returns pointer to next char. */ -static devmap_t * -interpret(char *val) +static char * +dmapdskip(p) + register char *p; { - register struct _dmapbuff *_dmap = _dmapalloc(); + while (*p && *p != ' ' && *p != '\n') + ++p; + if (*p != '\0') + *p++ = '\0'; - 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 (p); +} + +char * +getdmapfield(char *ptr) +{ + static char *tptr; - return (&interpdevmap); + if (ptr == NULL) + ptr = tptr; + if (ptr == NULL) + return (NULL); + tptr = dmapskip(ptr); + ptr = trim_white(ptr); + if (ptr == NULL) + return (NULL); + if (*ptr == NULL) + return (NULL); + + return (ptr); +} + +char * +getdmapdfield(char *ptr) +{ + static char *tptr; + if (ptr != NULL) { + ptr = trim_white(ptr); + } else { + ptr = tptr; + } + if (ptr == NULL) + return (NULL); + tptr = dmapdskip(ptr); + if (ptr == NULL) + return (NULL); + if (*ptr == NULL) + return (NULL); + + return (ptr); } diff --git a/usr/src/lib/libbsm/common/llib-lbsm b/usr/src/lib/libbsm/common/llib-lbsm index b95cf4f0d3..a00c330276 100644 --- a/usr/src/lib/libbsm/common/llib-lbsm +++ b/usr/src/lib/libbsm/common/llib-lbsm @@ -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> diff --git a/usr/src/lib/libbsm/mkhdr.sh b/usr/src/lib/libbsm/mkhdr.sh index ca1be7eaec..3de666cb2f 100644 --- a/usr/src/lib/libbsm/mkhdr.sh +++ b/usr/src/lib/libbsm/mkhdr.sh @@ -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 @@ HEADER_FILE=audit_uevents.h 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 @@ EOF 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 diff --git a/usr/src/lib/libbsm/spec/Makefile.targ b/usr/src/lib/libbsm/spec/Makefile.targ index a4a58c29f8..1784ff6015 100644 --- a/usr/src/lib/libbsm/spec/Makefile.targ +++ b/usr/src/lib/libbsm/spec/Makefile.targ @@ -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 @@ OBJECTS = au_open.o \ audit.o \ auditon.o \ auditsvc.o \ + devalloc.o \ exceptions.o \ getacinfo.o \ getauclassent.o \ diff --git a/usr/src/lib/libbsm/spec/devalloc.spec b/usr/src/lib/libbsm/spec/devalloc.spec new file mode 100644 index 0000000000..3861d93b6c --- /dev/null +++ b/usr/src/lib/libbsm/spec/devalloc.spec @@ -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 diff --git a/usr/src/lib/libbsm/spec/private.spec b/usr/src/lib/libbsm/spec/private.spec index 1435ae29e9..95cc9e1795 100644 --- a/usr/src/lib/libbsm/spec/private.spec +++ b/usr/src/lib/libbsm/spec/private.spec @@ -242,6 +242,18 @@ declaration token_t *au_to_xselect(char *pstring, char *type, \ 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 @@ declaration int cannot_audit(int force) 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 @@ declaration int _getacflg(au_acinfo_t *, char *, int) 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 @@ errno EAGAIN EBADF EBUSY EFBIG EINTR EINVAL EIO \ 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 diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index f5f2219db9..646428e3e4 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -772,6 +772,7 @@ PORTSYS= \ getpeerucred.o \ inst_sync.o \ issetugid.o \ + label.o \ libc_link.o \ libc_open.o \ lockf.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index 4e9df745fc..e4156e0ae6 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -811,6 +811,7 @@ PORTSYS= \ getpeerucred.o \ inst_sync.o \ issetugid.o \ + label.o \ libc_link.o \ libc_open.o \ lockf.o \ diff --git a/usr/src/lib/libc/inc/synonyms.h b/usr/src/lib/libc/inc/synonyms.h index b392b4140a..179f25f627 100644 --- a/usr/src/lib/libc/inc/synonyms.h +++ b/usr/src/lib/libc/inc/synonyms.h @@ -481,6 +481,7 @@ extern "C" { #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 @@ extern "C" { #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 diff --git a/usr/src/lib/libc/port/gen/ucred.c b/usr/src/lib/libc/port/gen/ucred.c index 8367c0f90c..b500617d48 100644 --- a/usr/src/lib/libc/port/gen/ucred.c +++ b/usr/src/lib/libc/port/gen/ucred.c @@ -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 @@ ucred_getzoneid(const ucred_t *uc) 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. */ diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc index 31c57bd49b..9930b72c9c 100644 --- a/usr/src/lib/libc/port/llib-lc +++ b/usr/src/lib/libc/port/llib-lc @@ -1740,3 +1740,6 @@ volatile sc_shared_t *volatile *_thr_schedctl(void); /* private interface to unmount all autofs mounts */ int _autofssys(enum autofssys_op, void *); + +/* label.c */ +extern int is_system_labeled(void); diff --git a/usr/src/lib/libc/port/sys/label.c b/usr/src/lib/libc/port/sys/label.c new file mode 100644 index 0000000000..15c476ba8d --- /dev/null +++ b/usr/src/lib/libc/port/sys/label.c @@ -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)); +} diff --git a/usr/src/lib/libc/port/sys/zone.c b/usr/src/lib/libc/port/sys/zone.c index fc852c4dd5..12e34c0de6 100644 --- a/usr/src/lib/libc/port/sys/zone.c +++ b/usr/src/lib/libc/port/sys/zone.c @@ -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 @@ zone_create(const char *name, const char *root, const struct priv_set *privs, 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)); } diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile index 587a8d0306..7b5a74a3a3 100644 --- a/usr/src/lib/libc/sparc/Makefile +++ b/usr/src/lib/libc/sparc/Makefile @@ -836,6 +836,7 @@ PORTSYS= \ getpeerucred.o \ inst_sync.o \ issetugid.o \ + label.o \ libc_link.o \ libc_open.o \ lockf.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile index d2c0bd1f8c..55d2c9d7be 100644 --- a/usr/src/lib/libc/sparcv9/Makefile +++ b/usr/src/lib/libc/sparcv9/Makefile @@ -781,6 +781,7 @@ PORTSYS= \ getpeerucred.o \ inst_sync.o \ issetugid.o \ + label.o \ libc_link.o \ libc_open.o \ lockf.o \ diff --git a/usr/src/lib/libc/spec/gen.spec b/usr/src/lib/libc/spec/gen.spec index cf7993a61c..55d40dd946 100644 --- a/usr/src/lib/libc/spec/gen.spec +++ b/usr/src/lib/libc/spec/gen.spec @@ -4698,6 +4698,17 @@ weak ucred_getzoneid 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) diff --git a/usr/src/lib/libc/spec/sys.spec b/usr/src/lib/libc/spec/sys.spec index 7b181ab7d5..1e928c42b8 100644 --- a/usr/src/lib/libc/spec/sys.spec +++ b/usr/src/lib/libc/spec/sys.spec @@ -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 @@ end 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 @@ function _getzonenamebyid 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 diff --git a/usr/src/lib/libc/spec/versions b/usr/src/lib/libc/spec/versions index 210eb67629..cbfc8b9c6b 100644 --- a/usr/src/lib/libc/spec/versions +++ b/usr/src/lib/libc/spec/versions @@ -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 @@ i386 { 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 @@ amd64 { 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 @@ sparc { 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}; diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.h b/usr/src/lib/libipsecutil/common/ipsec_util.h index 70bedb66bd..3e8876db93 100644 --- a/usr/src/lib/libipsecutil/common/ipsec_util.h +++ b/usr/src/lib/libipsecutil/common/ipsec_util.h @@ -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 @@ extern "C" { #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 diff --git a/usr/src/lib/libldap5/Makefile.com b/usr/src/lib/libldap5/Makefile.com index b641d18cd3..a90c72761d 100644 --- a/usr/src/lib/libldap5/Makefile.com +++ b/usr/src/lib/libldap5/Makefile.com @@ -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 @@ SRCS= $(BEROBJS:%.o=../sources/ldap/ber/%.c) \ LIBS = $(DYNLIB) $(LINTLIB) DYNFLAGS += $(ZNODELETE) -CPPFLAGS += -I$(COM_INC) +CPPFLAGS= $(COM_INC) $(CPPFLAGS.master) # definitions for lint diff --git a/usr/src/lib/libnsl/Makefile b/usr/src/lib/libnsl/Makefile index 756e9d14d1..04728bf54a 100644 --- a/usr/src/lib/libnsl/Makefile +++ b/usr/src/lib/libnsl/Makefile @@ -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 @@ CLEANFILES += $(DERIVED_FILES) # 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 @@ headers: $(PROTOCOL_DIR) .WAIT $(PROTOCOL_FILES) $(PROTOCOL_FILES_UTS) \ install: all $(SUBDIRS) +install_h: $(ROOTHDRS) + +# nss.h isn't delivered; no reason to check +check: + clean clobber delete lint package: $(SUBDIRS) $(PROTOCOL_DIR): diff --git a/usr/src/lib/libnsl/Makefile.com b/usr/src/lib/libnsl/Makefile.com index 7945cdb4c2..0159a59cba 100644 --- a/usr/src/lib/libnsl/Makefile.com +++ b/usr/src/lib/libnsl/Makefile.com @@ -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 @@ MAPOPTS= $(MAPFILES:%=-M%) # 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) diff --git a/usr/src/lib/libnsl/nss/nss.h b/usr/src/lib/libnsl/nss/nss.h index 7efd4e83ee..e3f1463dcd 100644 --- a/usr/src/lib/libnsl/nss/nss.h +++ b/usr/src/lib/libnsl/nss/nss.h @@ -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 _nss_initf_ipnodes(nss_db_params_t *); 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 diff --git a/usr/src/lib/libnsl/rpc/clnt_bcast.c b/usr/src/lib/libnsl/rpc/clnt_bcast.c index fc18ed6236..ab16e8a595 100644 --- a/usr/src/lib/libnsl/rpc/clnt_bcast.c +++ b/usr/src/lib/libnsl/rpc/clnt_bcast.c @@ -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 @@ rpc_broadcast_exp(const rpcprog_t prog, const rpcvers_t vers, 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); diff --git a/usr/src/lib/libnsl/rpc/clnt_generic.c b/usr/src/lib/libnsl/rpc/clnt_generic.c index add0dfe880..f3507134ce 100644 --- a/usr/src/lib/libnsl/rpc/clnt_generic.c +++ b/usr/src/lib/libnsl/rpc/clnt_generic.c @@ -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 @@ clnt_create_service_timed(const char *host, const char *service, 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 @@ _clnt_tli_create_timed(int fd, const struct netconfig *nconf, 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) { diff --git a/usr/src/lib/libnsl/rpc/rpc_mt.h b/usr/src/lib/libnsl/rpc/rpc_mt.h index 52b49c3a82..75e93f390f 100644 --- a/usr/src/lib/libnsl/rpc/rpc_mt.h +++ b/usr/src/lib/libnsl/rpc/rpc_mt.h @@ -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 int __getpublickey_cached(char *, char *, int *); 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 diff --git a/usr/src/lib/libnsl/rpc/svc_dg.c b/usr/src/lib/libnsl/rpc/svc_dg.c index 8a73cb8faa..b66ba988f0 100644 --- a/usr/src/lib/libnsl/rpc/svc_dg.c +++ b/usr/src/lib/libnsl/rpc/svc_dg.c @@ -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 @@ svc_dg_stat(SVCXPRT *xprt) 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 @@ again: /* 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 @@ svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) 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 @@ try_again: "svc_dg_reply: t_sndudata error t_errno=%d errno=%d\n", t_errno, errno); } + tu_data->opt.buf = (char *)su->opts; } return (stat); } diff --git a/usr/src/lib/libnsl/rpc/svc_generic.c b/usr/src/lib/libnsl/rpc/svc_generic.c index 10f6ce1508..a0673e43c8 100644 --- a/usr/src/lib/libnsl/rpc/svc_generic.c +++ b/usr/src/lib/libnsl/rpc/svc_generic.c @@ -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 @@ extern bool_t __rpc_try_doors(const char *, bool_t *); 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 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, 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 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, 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 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, 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 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, * 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 @@ svc_tli_create(const int ofd, const struct netconfig *nconf, 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 diff --git a/usr/src/lib/libnsl/rpc/ti_opts.c b/usr/src/lib/libnsl/rpc/ti_opts.c index 1b5e910261..ae32fa9788 100644 --- a/usr/src/lib/libnsl/rpc/ti_opts.c +++ b/usr/src/lib/libnsl/rpc/ti_opts.c @@ -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 @@ __rpc_tli_set_options(int fd, int optlevel, int optname, int optval) 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 @@ __tli_sys_strerror(char *buf, size_t buflen, int tli_err, int sys_err) (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); + } + } +} diff --git a/usr/src/lib/libsldap/common/ns_common.c b/usr/src/lib/libsldap/common/ns_common.c index b3a812e92f..05323c204b 100644 --- a/usr/src/lib/libsldap/common/ns_common.c +++ b/usr/src/lib/libsldap/common/ns_common.c @@ -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 @@ static ns_service_map ns_def_map[] = { { "profile", "ou=profile,", NULL }, { "printers", "ou=printers,", NULL }, { "automount", "", NULL }, + { "tnrhtp", "ou=ipTnet,", NULL }, + { "tnrhdb", "ou=ipTnet,", "tnrhtp" }, { NULL, NULL, NULL } }; diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h index 8e8c59113c..0138c1e3d5 100644 --- a/usr/src/lib/libsldap/common/ns_sldap.h +++ b/usr/src/lib/libsldap/common/ns_sldap.h @@ -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 @@ typedef struct _ns_automount { #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 diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c index 146752c88a..217586e340 100644 --- a/usr/src/lib/libsldap/common/ns_writes.c +++ b/usr/src/lib/libsldap/common/ns_writes.c @@ -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 @@ __s_cvt_audituser(const void *data, char **rdn, 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 @@ static __ns_cvt_type_t __s_cvtlist[] = { { 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 }, }; diff --git a/usr/src/lib/libtsnet/Makefile b/usr/src/lib/libtsnet/Makefile new file mode 100644 index 0000000000..aa06ccdef0 --- /dev/null +++ b/usr/src/lib/libtsnet/Makefile @@ -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 diff --git a/usr/src/lib/libtsnet/Makefile.com b/usr/src/lib/libtsnet/Makefile.com new file mode 100644 index 0000000000..c77b2403ad --- /dev/null +++ b/usr/src/lib/libtsnet/Makefile.com @@ -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 diff --git a/usr/src/lib/libtsnet/amd64/Makefile b/usr/src/lib/libtsnet/amd64/Makefile new file mode 100644 index 0000000000..69cf39010b --- /dev/null +++ b/usr/src/lib/libtsnet/amd64/Makefile @@ -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) diff --git a/usr/src/lib/libtsnet/common/libtsnet.h b/usr/src/lib/libtsnet/common/libtsnet.h new file mode 100644 index 0000000000..2aa6d5fc56 --- /dev/null +++ b/usr/src/lib/libtsnet/common/libtsnet.h @@ -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 */ diff --git a/usr/src/lib/libtsnet/common/llib-ltsnet b/usr/src/lib/libtsnet/common/llib-ltsnet new file mode 100644 index 0000000000..4dbadf3b68 --- /dev/null +++ b/usr/src/lib/libtsnet/common/llib-ltsnet @@ -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> diff --git a/usr/src/lib/libtsnet/common/misc.c b/usr/src/lib/libtsnet/common/misc.c new file mode 100644 index 0000000000..9e8c20cdc8 --- /dev/null +++ b/usr/src/lib/libtsnet/common/misc.c @@ -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")); +} diff --git a/usr/src/lib/libtsnet/common/synonyms.h b/usr/src/lib/libtsnet/common/synonyms.h new file mode 100644 index 0000000000..ed28e16910 --- /dev/null +++ b/usr/src/lib/libtsnet/common/synonyms.h @@ -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 */ diff --git a/usr/src/lib/libtsnet/common/tnmlp.c b/usr/src/lib/libtsnet/common/tnmlp.c new file mode 100644 index 0000000000..ea4e1c2fc9 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tnmlp.c @@ -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)); +} diff --git a/usr/src/lib/libtsnet/common/tnrh.c b/usr/src/lib/libtsnet/common/tnrh.c new file mode 100644 index 0000000000..3213005cc9 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tnrh.c @@ -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)); +} diff --git a/usr/src/lib/libtsnet/common/tnrhtp.c b/usr/src/lib/libtsnet/common/tnrhtp.c new file mode 100644 index 0000000000..9591b6ad60 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tnrhtp.c @@ -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)); +} diff --git a/usr/src/lib/libtsnet/common/tsol_getrhent.c b/usr/src/lib/libtsnet/common/tsol_getrhent.c new file mode 100644 index 0000000000..24455f0960 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_getrhent.c @@ -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); +} diff --git a/usr/src/lib/libtsnet/common/tsol_gettpent.c b/usr/src/lib/libtsnet/common/tsol_gettpent.c new file mode 100644 index 0000000000..ab20c85620 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_gettpent.c @@ -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); +} diff --git a/usr/src/lib/libtsnet/common/tsol_getzcent.c b/usr/src/lib/libtsnet/common/tsol_getzcent.c new file mode 100644 index 0000000000..4faf1cf5be --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_getzcent.c @@ -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); +} diff --git a/usr/src/lib/libtsnet/common/tsol_sgetrhent.c b/usr/src/lib/libtsnet/common/tsol_sgetrhent.c new file mode 100644 index 0000000000..5037b6b37a --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_sgetrhent.c @@ -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); +} diff --git a/usr/src/lib/libtsnet/common/tsol_sgettpent.c b/usr/src/lib/libtsnet/common/tsol_sgettpent.c new file mode 100644 index 0000000000..37fd75b234 --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_sgettpent.c @@ -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); +} diff --git a/usr/src/lib/libtsnet/common/tsol_sgetzcent.c b/usr/src/lib/libtsnet/common/tsol_sgetzcent.c new file mode 100644 index 0000000000..657c3be47c --- /dev/null +++ b/usr/src/lib/libtsnet/common/tsol_sgetzcent.c @@ -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); + } +} diff --git a/usr/src/lib/libtsnet/i386/Makefile b/usr/src/lib/libtsnet/i386/Makefile new file mode 100644 index 0000000000..ee3ea88a08 --- /dev/null +++ b/usr/src/lib/libtsnet/i386/Makefile @@ -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) diff --git a/usr/src/lib/libtsnet/sparc/Makefile b/usr/src/lib/libtsnet/sparc/Makefile new file mode 100644 index 0000000000..73ba2bbce8 --- /dev/null +++ b/usr/src/lib/libtsnet/sparc/Makefile @@ -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) diff --git a/usr/src/lib/libtsnet/sparcv9/Makefile b/usr/src/lib/libtsnet/sparcv9/Makefile new file mode 100644 index 0000000000..69cf39010b --- /dev/null +++ b/usr/src/lib/libtsnet/sparcv9/Makefile @@ -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) diff --git a/usr/src/lib/libtsnet/spec/Makefile b/usr/src/lib/libtsnet/spec/Makefile new file mode 100644 index 0000000000..66c61a6d05 --- /dev/null +++ b/usr/src/lib/libtsnet/spec/Makefile @@ -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 diff --git a/usr/src/lib/libtsnet/spec/Makefile.targ b/usr/src/lib/libtsnet/spec/Makefile.targ new file mode 100644 index 0000000000..aeafa46121 --- /dev/null +++ b/usr/src/lib/libtsnet/spec/Makefile.targ @@ -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../../ diff --git a/usr/src/cmd/dminfo/Makefile b/usr/src/lib/libtsnet/spec/amd64/Makefile index 481229df1d..03d9b122a2 100644 --- a/usr/src/cmd/dminfo/Makefile +++ b/usr/src/lib/libtsnet/spec/amd64/Makefile @@ -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,36 +19,15 @@ # CDDL HEADER END # # -# Copyright 1989, 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" # -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 +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/Makefile.lib.64 +include $(SRC)/lib/Makefile.spec diff --git a/usr/src/lib/libtsnet/spec/i386/Makefile b/usr/src/lib/libtsnet/spec/i386/Makefile new file mode 100644 index 0000000000..b378e293ca --- /dev/null +++ b/usr/src/lib/libtsnet/spec/i386/Makefile @@ -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 diff --git a/usr/src/lib/libtsnet/spec/sparc/Makefile b/usr/src/lib/libtsnet/spec/sparc/Makefile new file mode 100644 index 0000000000..013c8f71b0 --- /dev/null +++ b/usr/src/lib/libtsnet/spec/sparc/Makefile @@ -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 diff --git a/usr/src/lib/libtsnet/spec/sparcv9/Makefile b/usr/src/lib/libtsnet/spec/sparcv9/Makefile new file mode 100644 index 0000000000..03d9b122a2 --- /dev/null +++ b/usr/src/lib/libtsnet/spec/sparcv9/Makefile @@ -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 diff --git a/usr/src/lib/libtsnet/spec/tsnet.spec b/usr/src/lib/libtsnet/spec/tsnet.spec new file mode 100644 index 0000000000..78e222075d --- /dev/null +++ b/usr/src/lib/libtsnet/spec/tsnet.spec @@ -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 diff --git a/usr/src/lib/libtsnet/spec/versions b/usr/src/lib/libtsnet/spec/versions new file mode 100644 index 0000000000..43c70977f7 --- /dev/null +++ b/usr/src/lib/libtsnet/spec/versions @@ -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; +} diff --git a/usr/src/lib/libtsol/Makefile b/usr/src/lib/libtsol/Makefile new file mode 100644 index 0000000000..2bb6a81725 --- /dev/null +++ b/usr/src/lib/libtsol/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/Makefile.com b/usr/src/lib/libtsol/Makefile.com new file mode 100644 index 0000000000..46959e7662 --- /dev/null +++ b/usr/src/lib/libtsol/Makefile.com @@ -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 diff --git a/usr/src/lib/libtsol/amd64/Makefile b/usr/src/lib/libtsol/amd64/Makefile new file mode 100644 index 0000000000..69cf39010b --- /dev/null +++ b/usr/src/lib/libtsol/amd64/Makefile @@ -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) diff --git a/usr/src/lib/libtsol/common/btohex.c b/usr/src/lib/libtsol/common/btohex.c new file mode 100644 index 0000000000..19122382c7 --- /dev/null +++ b/usr/src/lib/libtsol/common/btohex.c @@ -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)); +} diff --git a/usr/src/lib/libtsol/common/btos.c b/usr/src/lib/libtsol/common/btos.c new file mode 100644 index 0000000000..7ed4a6cdee --- /dev/null +++ b/usr/src/lib/libtsol/common/btos.c @@ -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 */ diff --git a/usr/src/lib/libtsol/common/call_labeld.c b/usr/src/lib/libtsol/common/call_labeld.c new file mode 100644 index 0000000000..35d94450f5 --- /dev/null +++ b/usr/src/lib/libtsol/common/call_labeld.c @@ -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, ¶m) < 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 */ diff --git a/usr/src/lib/libtsol/common/clnt.h b/usr/src/lib/libtsol/common/clnt.h new file mode 100644 index 0000000000..bf3845e02c --- /dev/null +++ b/usr/src/lib/libtsol/common/clnt.h @@ -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 */ diff --git a/usr/src/lib/libtsol/common/getlabel.c b/usr/src/lib/libtsol/common/getlabel.c new file mode 100644 index 0000000000..9cca4019f0 --- /dev/null +++ b/usr/src/lib/libtsol/common/getlabel.c @@ -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)); +} diff --git a/usr/src/lib/libtsol/common/getpathbylabel.c b/usr/src/lib/libtsol/common/getpathbylabel.c new file mode 100644 index 0000000000..0f8c5597d0 --- /dev/null +++ b/usr/src/lib/libtsol/common/getpathbylabel.c @@ -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() */ diff --git a/usr/src/lib/libtsol/common/getplabel.c b/usr/src/lib/libtsol/common/getplabel.c new file mode 100644 index 0000000000..49aeeb66fe --- /dev/null +++ b/usr/src/lib/libtsol/common/getplabel.c @@ -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); +} diff --git a/usr/src/lib/libtsol/common/hextob.c b/usr/src/lib/libtsol/common/hextob.c new file mode 100644 index 0000000000..758969e688 --- /dev/null +++ b/usr/src/lib/libtsol/common/hextob.c @@ -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); +} diff --git a/usr/src/lib/libtsol/common/label.h b/usr/src/lib/libtsol/common/label.h new file mode 100644 index 0000000000..6a5bfdc205 --- /dev/null +++ b/usr/src/lib/libtsol/common/label.h @@ -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 */ diff --git a/usr/src/lib/libtsol/common/labeld.h b/usr/src/lib/libtsol/common/labeld.h new file mode 100644 index 0000000000..aa95982998 --- /dev/null +++ b/usr/src/lib/libtsol/common/labeld.h @@ -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 */ diff --git a/usr/src/lib/libtsol/common/llib-ltsol b/usr/src/lib/libtsol/common/llib-ltsol new file mode 100644 index 0000000000..1d4acc5a3a --- /dev/null +++ b/usr/src/lib/libtsol/common/llib-ltsol @@ -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> diff --git a/usr/src/lib/libtsol/common/ltos.c b/usr/src/lib/libtsol/common/ltos.c new file mode 100644 index 0000000000..16feabbf41 --- /dev/null +++ b/usr/src/lib/libtsol/common/ltos.c @@ -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 +} diff --git a/usr/src/lib/libtsol/common/misc.c b/usr/src/lib/libtsol/common/misc.c new file mode 100644 index 0000000000..14113f22be --- /dev/null +++ b/usr/src/lib/libtsol/common/misc.c @@ -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); +} diff --git a/usr/src/lib/libtsol/common/private.c b/usr/src/lib/libtsol/common/private.c new file mode 100644 index 0000000000..3052624f1c --- /dev/null +++ b/usr/src/lib/libtsol/common/private.c @@ -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 diff --git a/usr/src/lib/libtsol/common/privlib.c b/usr/src/lib/libtsol/common/privlib.c new file mode 100644 index 0000000000..3d1a8023d2 --- /dev/null +++ b/usr/src/lib/libtsol/common/privlib.c @@ -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() */ diff --git a/usr/src/lib/libtsol/common/setflabel.c b/usr/src/lib/libtsol/common/setflabel.c new file mode 100644 index 0000000000..1d645c8d23 --- /dev/null +++ b/usr/src/lib/libtsol/common/setflabel.c @@ -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); +} diff --git a/usr/src/lib/libtsol/common/stob.c b/usr/src/lib/libtsol/common/stob.c new file mode 100644 index 0000000000..e8e6780875 --- /dev/null +++ b/usr/src/lib/libtsol/common/stob.c @@ -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 diff --git a/usr/src/lib/libtsol/common/stol.c b/usr/src/lib/libtsol/common/stol.c new file mode 100644 index 0000000000..2a951b3907 --- /dev/null +++ b/usr/src/lib/libtsol/common/stol.c @@ -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); +} diff --git a/usr/src/lib/libtsol/common/zone.c b/usr/src/lib/libtsol/common/zone.c new file mode 100644 index 0000000000..6e4b2970a2 --- /dev/null +++ b/usr/src/lib/libtsol/common/zone.c @@ -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); +} diff --git a/usr/src/lib/libtsol/i386/Makefile b/usr/src/lib/libtsol/i386/Makefile new file mode 100644 index 0000000000..fb5e32504a --- /dev/null +++ b/usr/src/lib/libtsol/i386/Makefile @@ -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) diff --git a/usr/src/lib/libtsol/sparc/Makefile b/usr/src/lib/libtsol/sparc/Makefile new file mode 100644 index 0000000000..4addab0cae --- /dev/null +++ b/usr/src/lib/libtsol/sparc/Makefile @@ -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) diff --git a/usr/src/lib/libtsol/sparcv9/Makefile b/usr/src/lib/libtsol/sparcv9/Makefile new file mode 100644 index 0000000000..69cf39010b --- /dev/null +++ b/usr/src/lib/libtsol/sparcv9/Makefile @@ -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) diff --git a/usr/src/lib/libtsol/spec/Makefile b/usr/src/lib/libtsol/spec/Makefile new file mode 100644 index 0000000000..835bbc66f1 --- /dev/null +++ b/usr/src/lib/libtsol/spec/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/spec/Makefile.targ b/usr/src/lib/libtsol/spec/Makefile.targ new file mode 100644 index 0000000000..e76d79a49d --- /dev/null +++ b/usr/src/lib/libtsol/spec/Makefile.targ @@ -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 diff --git a/usr/src/lib/libtsol/spec/amd64/Makefile b/usr/src/lib/libtsol/spec/amd64/Makefile new file mode 100644 index 0000000000..03d9b122a2 --- /dev/null +++ b/usr/src/lib/libtsol/spec/amd64/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/spec/i386/Makefile b/usr/src/lib/libtsol/spec/i386/Makefile new file mode 100644 index 0000000000..7aab1a07a8 --- /dev/null +++ b/usr/src/lib/libtsol/spec/i386/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/spec/obsolete.spec b/usr/src/lib/libtsol/spec/obsolete.spec new file mode 100644 index 0000000000..ccebc2f8b9 --- /dev/null +++ b/usr/src/lib/libtsol/spec/obsolete.spec @@ -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 diff --git a/usr/src/lib/libtsol/spec/private.spec b/usr/src/lib/libtsol/spec/private.spec new file mode 100644 index 0000000000..c5e66ea7b6 --- /dev/null +++ b/usr/src/lib/libtsol/spec/private.spec @@ -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 diff --git a/usr/src/lib/libtsol/spec/sparc/Makefile b/usr/src/lib/libtsol/spec/sparc/Makefile new file mode 100644 index 0000000000..7aab1a07a8 --- /dev/null +++ b/usr/src/lib/libtsol/spec/sparc/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/spec/sparcv9/Makefile b/usr/src/lib/libtsol/spec/sparcv9/Makefile new file mode 100644 index 0000000000..03d9b122a2 --- /dev/null +++ b/usr/src/lib/libtsol/spec/sparcv9/Makefile @@ -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 diff --git a/usr/src/lib/libtsol/spec/tsol.spec b/usr/src/lib/libtsol/spec/tsol.spec new file mode 100644 index 0000000000..089f5eb2ec --- /dev/null +++ b/usr/src/lib/libtsol/spec/tsol.spec @@ -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 diff --git a/usr/src/lib/libtsol/spec/versions b/usr/src/lib/libtsol/spec/versions new file mode 100644 index 0000000000..40f1cccb72 --- /dev/null +++ b/usr/src/lib/libtsol/spec/versions @@ -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; +} diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c index 36862ce976..cede45643a 100644 --- a/usr/src/lib/libzonecfg/common/libzonecfg.c +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c @@ -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 @@ static const char *default_priv_list[] = { 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 @@ get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 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) diff --git a/usr/src/lib/nsswitch/files/Makefile.com b/usr/src/lib/nsswitch/files/Makefile.com index e71a2db442..f6105144d7 100644 --- a/usr/src/lib/nsswitch/files/Makefile.com +++ b/usr/src/lib/nsswitch/files/Makefile.com @@ -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 @@ OBJECTS = bootparams_getbyname.o \ getexecattr.o \ getuserattr.o \ getauuser.o \ - netmasks.o + netmasks.o \ + tsol_getrhent.o \ + tsol_gettpent.o # include common nsswitch library definitions. include ../../Makefile.com diff --git a/usr/src/lib/nsswitch/files/common/mapfile-vers b/usr/src/lib/nsswitch/files/common/mapfile-vers index a4c6b1b67f..7210caf3d7 100644 --- a/usr/src/lib/nsswitch/files/common/mapfile-vers +++ b/usr/src/lib/nsswitch/files/common/mapfile-vers @@ -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 @@ SUNWprivate_1.1 { _nss_files_services_constr; _nss_files_shadow_constr; _nss_files_user_attr_constr; + _nss_files_tnrhdb_constr; + _nss_files_tnrhtp_constr; local: *; }; diff --git a/usr/src/lib/nsswitch/files/common/tsol_getrhent.c b/usr/src/lib/nsswitch/files/common/tsol_getrhent.c new file mode 100644 index 0000000000..f41f606034 --- /dev/null +++ b/usr/src/lib/nsswitch/files/common/tsol_getrhent.c @@ -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)); +} diff --git a/usr/src/lib/nsswitch/files/common/tsol_gettpent.c b/usr/src/lib/nsswitch/files/common/tsol_gettpent.c new file mode 100644 index 0000000000..ae5e9ca2be --- /dev/null +++ b/usr/src/lib/nsswitch/files/common/tsol_gettpent.c @@ -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)); +} diff --git a/usr/src/lib/nsswitch/ldap/Makefile.com b/usr/src/lib/nsswitch/ldap/Makefile.com index 03d14aa6a7..031dd04f46 100644 --- a/usr/src/lib/nsswitch/ldap/Makefile.com +++ b/usr/src/lib/nsswitch/ldap/Makefile.com @@ -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 @@ OBJECTS = getauthattr.o \ getservent.o \ getspent.o \ getuserattr.o \ + tsol_getrhent.o \ + tsol_gettpent.o \ ldap_common.o \ ldap_utils.o diff --git a/usr/src/lib/nsswitch/ldap/common/ldap_common.c b/usr/src/lib/nsswitch/ldap/common/ldap_common.c index 06acfe2e9b..9d961d9d1d 100644 --- a/usr/src/lib/nsswitch/ldap/common/ldap_common.c +++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.c @@ -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 @@ static struct gettablefilter { {(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} }; diff --git a/usr/src/lib/nsswitch/ldap/common/ldap_common.h b/usr/src/lib/nsswitch/ldap/common/ldap_common.h index 292abfba54..23d5e2b1ae 100644 --- a/usr/src/lib/nsswitch/ldap/common/ldap_common.h +++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.h @@ -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 @@ extern "C" { #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) diff --git a/usr/src/lib/nsswitch/ldap/common/mapfile-vers b/usr/src/lib/nsswitch/ldap/common/mapfile-vers index 9daed00900..ae31444846 100644 --- a/usr/src/lib/nsswitch/ldap/common/mapfile-vers +++ b/usr/src/lib/nsswitch/ldap/common/mapfile-vers @@ -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 @@ SUNWprivate_1.1 { _nss_ldap_shadow_constr; _nss_ldap_publickey_constr; _nss_ldap_user_attr_constr; + _nss_ldap_tnrhdb_constr; + _nss_ldap_tnrhtp_constr; local: *; }; diff --git a/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c b/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c new file mode 100644 index 0000000000..90a21988a2 --- /dev/null +++ b/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c @@ -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)); +} diff --git a/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c b/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c new file mode 100644 index 0000000000..b7f5423f6f --- /dev/null +++ b/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c @@ -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)); +} diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com index 3358fa9ffb..a29c6ce916 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_com +++ b/usr/src/pkgdefs/SUNWarc/prototype_com @@ -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 644 root bin 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 diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386 index a881a19b74..9183554f52 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarc/prototype_i386 @@ -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=../../../lib/amd64/llib-lcurses 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 diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc index 34253cea18..b0a2e26329 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc @@ -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=../../../lib/sparcv9/llib-lcurses 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 diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_com b/usr/src/pkgdefs/SUNWarcr/prototype_com index 34649f372b..97ec6b58d5 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_com +++ b/usr/src/pkgdefs/SUNWarcr/prototype_com @@ -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.ln=./llib-lcurses.ln 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 diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_i386 b/usr/src/pkgdefs/SUNWarcr/prototype_i386 index f581edba71..9067000c99 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarcr/prototype_i386 @@ -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-ltermcap=./llib-lcurses 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 diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_sparc b/usr/src/pkgdefs/SUNWarcr/prototype_sparc index e07a8d17d9..749986b4f9 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarcr/prototype_sparc @@ -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-ltermcap=./llib-lcurses 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 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index 1ae7b07404..db4463ed17 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -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=../../lib/libthread.so.1 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 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index 4b0fc29ff3..d166c38401 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -197,6 +197,10 @@ f none usr/lib/amd64/lib450.so.1 755 root bin 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 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index 50e3ceae22..ec3a29ce8b 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -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=../../../lib/sparcv9/libcurses.so.1 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 diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_com b/usr/src/pkgdefs/SUNWcslr/prototype_com index 15f1c5dd48..b02e237504 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_com +++ b/usr/src/pkgdefs/SUNWcslr/prototype_com @@ -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 @@ f none lib/libthread.so.1 755 root bin 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 diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_i386 b/usr/src/pkgdefs/SUNWcslr/prototype_i386 index 980114658f..300ab68c3b 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcslr/prototype_i386 @@ -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 @@ s none lib/amd64/libthread.so=libthread.so.1 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 diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_sparc b/usr/src/pkgdefs/SUNWcslr/prototype_sparc index 6e8369140b..4ec7297175 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcslr/prototype_sparc @@ -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 @@ s none lib/sparcv9/libthread.so=libthread.so.1 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 diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index e464b29c63..d70ea97e23 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -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/sr0 400 root bin 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 diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 23d350314e..f855a12975 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -685,7 +685,7 @@ d none usr/sbin 755 root bin 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 @@ s none usr/sbin/cachefswssize=../lib/fs/cachefs/cachefswssize 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/ipsecalgs 555 root bin 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 @@ f none usr/sbin/installboot 555 root sys d none usr/xpg4 755 root bin d none usr/xpg4/bin 755 root bin f none usr/xpg4/bin/sh 555 root bin - diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index 21c0e46b32..5fe00a2666 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -189,6 +189,7 @@ f none usr/include/libscf_priv.h 0644 root bin 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/todio.h 0644 root bin 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.h 644 root bin 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 diff --git a/usr/src/pkgdefs/common_files/i.nsswitch b/usr/src/pkgdefs/common_files/i.nsswitch index 3e4006a32f..a14c96ba4e 100644 --- a/usr/src/pkgdefs/common_files/i.nsswitch +++ b/usr/src/pkgdefs/common_files/i.nsswitch @@ -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 @@ do 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 diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index 32d3cc9595..154ae5457a 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -52,6 +52,7 @@ usr/include/rpcsvc/daemon_utils.h i386 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/include/sys/scsi/adapters/mpapi_scsi_vhci.h i386 # 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 diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 2206e16103..51a9805f39 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -43,6 +43,7 @@ usr/include/rpcsvc/daemon_utils.h sparc 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 @@ usr/include/sys/scsi/adapters/mpapi_scsi_vhci.h sparc # 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 diff --git a/usr/src/tools/abi/etc/exceptions b/usr/src/tools/abi/etc/exceptions index 484e0d6948..586d9e50b4 100644 --- a/usr/src/tools/abi/etc/exceptions +++ b/usr/src/tools/abi/etc/exceptions @@ -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 @@ PSARC 2002/547: RULE W3: usr/lib/libinetsvc.so.1 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 ############################################# diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 6c28a71969..f735d270c7 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -77,6 +77,7 @@ GENUNIX_OBJS += \ bdev_dsort.o \ bio.o \ bitmap.o \ + blabel.o \ callb.o \ callout.o \ chdir.o \ @@ -162,6 +163,7 @@ GENUNIX_OBJS += \ kmem.o \ ksyms_snapshot.o \ l_strplumb.o \ + labelsys.o \ link.o \ list.o \ lockstat_subr.o \ @@ -297,6 +299,7 @@ GENUNIX_OBJS += \ times.o \ timers.o \ thread.o \ + tlabel.o \ tnf_res.o \ turnstile.o \ tty_common.o \ @@ -426,7 +429,7 @@ IP_SCTP_OBJS = sctp_crc32.o sctp.o sctp_opt_data.o sctp_output.o \ 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 \ diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index 3a214afab7..24ab2e0f46 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -828,6 +828,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/tnf/%.c $(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/syscall/%.c $(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)) diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c index 0ab2dba4d7..9052875bb5 100644 --- a/usr/src/uts/common/c2/audit.c +++ b/usr/src/uts/common/c2/audit.c @@ -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 @@ audit_savepath( return (0); } + tad->tad_ctrl |= PAD_NOPATH; /* prevent possible reentry */ + audit_pathbuild(pnp); tad->tad_vn = vp; @@ -348,6 +350,7 @@ audit_savepath( if (tad->tad_ctrl & PAD_MLD) tad->tad_ctrl |= PAD_PATHFND; + tad->tad_ctrl &= ~PAD_NOPATH; /* restore */ return (0); } @@ -703,6 +706,7 @@ audit_attributes(struct vnode *vp) tad->tad_ctrl |= PAD_NOAUDIT; } else { au_uwrite(au_to_attr(&attr)); + audit_sec_attributes(&(u_ad), vp); } } } @@ -920,6 +924,10 @@ audit_core_finish(int code) /* 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 @@ audit_closef(struct file *fp) 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 @@ audit_closef(struct file *fp) /* 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 @@ audit_reboot(void) /* 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 @@ audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names, /* 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 @@ audit_kssl(int cmd, void *params, int error) /* 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 @@ audit_kssl(int cmd, void *params, int error) 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 */ diff --git a/usr/src/uts/common/c2/audit.h b/usr/src/uts/common/c2/audit.h index f8c0ffd743..b3b3cbc308 100644 --- a/usr/src/uts/common/c2/audit.h +++ b/usr/src/uts/common/c2/audit.h @@ -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 @@ typedef au_id_t auid_t; #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 @@ typedef au_id_t auid_t; #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_setppriv(int, int, const struct priv_set *, const cred_t *); 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 diff --git a/usr/src/uts/common/c2/audit_event.c b/usr/src/uts/common/c2/audit_event.c index 1d5ba5a1be..4ee95e1728 100644 --- a/usr/src/uts/common/c2/audit_event.c +++ b/usr/src/uts/common/c2/audit_event.c @@ -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 @@ aus_kill(struct t_audit_data *tad) 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 @@ aus_close(struct t_audit_data *tad) 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 @@ aus_close(struct t_audit_data *tad) releasef(fd); return; } + au_uwrite(au_to_attr(&attr)); + audit_sec_attributes(&(u_ad), vp); } } } diff --git a/usr/src/uts/common/c2/audit_kevents.h b/usr/src/uts/common/c2/audit_kevents.h index ab184e973a..310b6d3ddf 100644 --- a/usr/src/uts/common/c2/audit_kevents.h +++ b/usr/src/uts/common/c2/audit_kevents.h @@ -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 @@ extern "C" { * * 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 @@ extern "C" { #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 @@ extern "C" { #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 @@ extern "C" { #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 } diff --git a/usr/src/uts/common/c2/audit_record.h b/usr/src/uts/common/c2/audit_record.h index b6bbcbbbe5..50ac50d689 100644 --- a/usr/src/uts/common/c2/audit_record.h +++ b/usr/src/uts/common/c2/audit_record.h @@ -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_socket_ex(short, short, char *, char *); 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(char, int); 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_process_ex(au_id_t, uid_t, gid_t, uid_t, gid_t, 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 *); diff --git a/usr/src/uts/common/c2/audit_start.c b/usr/src/uts/common/c2/audit_start.c index 1e5fbb58fc..9b772dc0d5 100644 --- a/usr/src/uts/common/c2/audit_start.c +++ b/usr/src/uts/common/c2/audit_start.c @@ -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 @@ audit_finish( /* 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, diff --git a/usr/src/uts/common/c2/audit_token.c b/usr/src/uts/common/c2/audit_token.c index 6999e79f6f..915ee051d2 100644 --- a/usr/src/uts/common/c2/audit_token.c +++ b/usr/src/uts/common/c2/audit_token.c @@ -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 @@ au_to_ipc_perm(struct kipc_perm *perm) 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 @@ au_to_privset( 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); +} diff --git a/usr/src/uts/common/disp/thread.c b/usr/src/uts/common/disp/thread.c index d9dfeb4993..0d6ec7ddac 100644 --- a/usr/src/uts/common/disp/thread.c +++ b/usr/src/uts/common/disp/thread.c @@ -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 @@ thread_init(void) 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); diff --git a/usr/src/uts/common/fs/autofs/auto_vfsops.c b/usr/src/uts/common/fs/autofs/auto_vfsops.c index ff8eee15cd..69375c42a9 100644 --- a/usr/src/uts/common/fs/autofs/auto_vfsops.c +++ b/usr/src/uts/common/fs/autofs/auto_vfsops.c @@ -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> diff --git a/usr/src/uts/common/fs/doorfs/door_vnops.c b/usr/src/uts/common/fs/doorfs/door_vnops.c index 2dee792704..3e7b420533 100644 --- a/usr/src/uts/common/fs/doorfs/door_vnops.c +++ b/usr/src/uts/common/fs/doorfs/door_vnops.c @@ -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 @@ const fs_operation_def_t door_vnodeops_template[] = { 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); } diff --git a/usr/src/uts/common/fs/lofs/lofs_vfsops.c b/usr/src/uts/common/fs/lofs/lofs_vfsops.c index d06f661005..edae6278ee 100644 --- a/usr/src/uts/common/fs/lofs/lofs_vfsops.c +++ b/usr/src/uts/common/fs/lofs/lofs_vfsops.c @@ -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 @@ static struct modlinkage modlinkage = { /* * This is the module initialization routine. */ + int -_init() +_init(void) { int status; @@ -139,8 +142,9 @@ _init() * 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 @@ lo_mount(struct vfs *vfsp, 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 @@ lo_mount(struct vfs *vfsp, 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 diff --git a/usr/src/uts/common/fs/nfs/nfs3_vfsops.c b/usr/src/uts/common/fs/nfs/nfs3_vfsops.c index efba329cc6..42a78c3d9e 100644 --- a/usr/src/uts/common/fs/nfs/nfs3_vfsops.c +++ b/usr/src/uts/common/fs/nfs/nfs3_vfsops.c @@ -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 @@ nfs3_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 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 @@ more: /* * 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 @@ more: * 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 @@ errout: if (rtvp != NULL) VN_RELE(rtvp); + if (mntzone != NULL) + zone_rele(mntzone); + return (error); } diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c index 1b705c4956..c0222cc6e2 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_srv.c +++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c @@ -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 @@ static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY; #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 @@ rfs4_op_secinfo_free(nfs_resop4 *resop) 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 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 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 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, *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 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 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 @@ do_rfs4_op_lookup(char *nm, uint_t buflen, struct svc_req *req, } } + /* + * 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 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, uint_t len; rfs4_file_t *fp; int in_crit = 0; + bslabel_t *clabel; /* CURRENT_FH: directory */ dvp = cs->vp; @@ -3669,6 +3793,29 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, } } + /* 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_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 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 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 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 @@ rfs4_op_setattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, { 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 @@ rfs4_op_setattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 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 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, 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 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, bool_t trunc; caller_context_t ct; component4 *component; + bslabel_t *clabel; sarg.sbp = &sb; @@ -5586,6 +5776,20 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, 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. diff --git a/usr/src/uts/common/fs/nfs/nfs4_subr.c b/usr/src/uts/common/fs/nfs/nfs4_subr.c index 5c6dd2d146..a041090bfc 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_subr.c +++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c @@ -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 unsigned int minimum_timeo[] = { 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, } 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, !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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, } clfree4(client, ch, nfscl); + if (cred_cloned) + crfree(cr); ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0); diff --git a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c index bea840c453..aa0f2c732c 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c +++ b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c @@ -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 @@ nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 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 @@ more: /* * 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 @@ more: * 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 @@ errout: /* * 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 @@ errout: 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 @@ errout: if (rtvp != NULL) VN_RELE(rtvp); + if (mntzone != NULL) + zone_rele(mntzone); + return (error); } diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c index 8e1751a452..05e70935be 100644 --- a/usr/src/uts/common/fs/nfs/nfs_subr.c +++ b/usr/src/uts/common/fs/nfs/nfs_subr.c @@ -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_freeh(AUTH *); 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 @@ rfs3call(mntinfo_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ failoverretry: } } + /* 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 @@ failoverretry: * the transfer size changed. */ clfree_impl(client, ch, nfscl); + if (cred_cloned) + crfree(cr); return (ENFS_TRYAGAIN); } } @@ -1348,6 +1367,8 @@ failoverretry: } clfree_impl(client, ch, nfscl); + if (cred_cloned) + crfree(cr); ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0); @@ -1449,11 +1470,13 @@ acl3call(mntinfo_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, 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 @@ failoverretry: } } + /* 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 @@ failoverretry: 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 @@ failoverretry: * the transfer size changed. */ clfree_impl(client, ch, nfscl); + if (cred_cloned) + crfree(cr); return (ENFS_TRYAGAIN); } #endif @@ -1921,6 +1956,8 @@ failoverretry: } clfree_impl(client, ch, nfscl); + if (cred_cloned) + crfree(cr); ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0); @@ -4972,3 +5009,111 @@ nfs_zoneid(void) { 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); +} diff --git a/usr/src/uts/common/fs/nfs/nfs_vfsops.c b/usr/src/uts/common/fs/nfs/nfs_vfsops.c index e9353d1e82..9eb64a301a 100644 --- a/usr/src/uts/common/fs/nfs/nfs_vfsops.c +++ b/usr/src/uts/common/fs/nfs/nfs_vfsops.c @@ -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 @@ nfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 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 @@ more: /* * 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 @@ more: * 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 @@ errout: if (rtvp != NULL) VN_RELE(rtvp); + if (mntzone != NULL) + zone_rele(mntzone); + return (error); } diff --git a/usr/src/uts/common/fs/sockfs/socksyscalls.c b/usr/src/uts/common/fs/sockfs/socksyscalls.c index a4681c134a..765ff83e0c 100644 --- a/usr/src/uts/common/fs/sockfs/socksyscalls.c +++ b/usr/src/uts/common/fs/sockfs/socksyscalls.c @@ -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> diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index e699a42255..1618e95bdd 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -51,6 +51,7 @@ extern "C" { #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 @@ typedef uint32_t ipaddr_t; #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 @@ typedef uint32_t ipaddr_t; #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 @@ typedef struct ipndp_s { } 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 @@ typedef struct ire_s { 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 @@ struct ip6_pkt_s { }; 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 @@ typedef struct in_pktinfo { } 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 int ip_srcid_report(queue_t *, mblk_t *, caddr_t, cred_t *); 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_restart_optmgmt(ipsq_t *, queue_t *, mblk_t *, void *); 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 @@ extern boolean_t ip_md_zcopy_attr(struct multidata_s *, struct pdesc_s *, 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 @@ struct ill_dls_capab_s { }; /* + * 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; diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c index 445b18f868..df8c33bb4b 100644 --- a/usr/src/uts/common/inet/ip/icmp.c +++ b/usr/src/uts/common/inet/ip/icmp.c @@ -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 int icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); 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 @@ icmp_connect(queue_t *q, mblk_t *mp) linkb(mp1, mp); linkb(mp1, mp2); + mblk_setcred(mp1, icmp->icmp_credp); putnext(q, mp1); } @@ -623,6 +626,10 @@ icmp_close(queue_t *q) 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_close(queue_t *q) 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 @@ icmp_ip_bind_mp(icmp_t *icmp, t_scalar_t bind_prim, t_scalar_t addr_length, 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 @@ icmp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) { 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 @@ icmp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) */ 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_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 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 @@ icmp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 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 @@ icmp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 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 @@ icmp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 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_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 (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; - } + 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); } + 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 @@ icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_build_hdrs(queue_t *q, icmp_t *icmp) } /* - * 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 @@ icmp_rput(queue_t *q, mblk_t *mp) 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 @@ icmp_rput(queue_t *q, mblk_t *mp) /* Initialize */ ipp.ipp_fields = 0; + hopstrip = 0; ip6h = (ip6_t *)rptr; /* @@ -3214,6 +3234,52 @@ icmp_rput(queue_t *q, mblk_t *mp) 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 @@ icmp_rput(queue_t *q, mblk_t *mp) 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 @@ icmp_rput(queue_t *q, mblk_t *mp) 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 @@ icmp_wput_hdrincl(queue_t *q, mblk_t *mp, icmp_t *icmp) */ (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 @@ icmp_wput(queue_t *q, mblk_t *mp) 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 @@ icmp_wput(queue_t *q, mblk_t *mp) /* Extract and ipaddr */ v4dst = sin->sin_addr.s_addr; break; + + default: + ASSERT(0); } /* @@ -3983,12 +4107,24 @@ icmp_wput(queue_t *q, mblk_t *mp) */ } + 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 @@ icmp_wput(queue_t *q, mblk_t *mp) * 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 @@ icmp_wput(queue_t *q, mblk_t *mp) } 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 @@ icmp_wput_ipv6(queue_t *q, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen) 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 @@ icmp_wput_ipv6(queue_t *q, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen) 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 @@ no_options: /* * 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 @@ no_options: /* We're done. Pass the packet to IP */ BUMP_MIB(&rawip_mib, rawipOutDatagrams); + mblk_setcred(mp1, icmp->icmp_credp); putnext(q, mp1); } diff --git a/usr/src/uts/common/inet/ip/icmp_opt_data.c b/usr/src/uts/common/inet/ip/icmp_opt_data.c index 8ada45dc0c..515880c03d 100644 --- a/usr/src/uts/common/inet/ip/icmp_opt_data.c +++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c @@ -87,6 +87,8 @@ opdes_t icmp_opt_arr[] = { 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), diff --git a/usr/src/uts/common/inet/ip/igmp.c b/usr/src/uts/common/inet/ip/igmp.c index 49877722d8..b38e421dc5 100644 --- a/usr/src/uts/common/inet/ip/igmp.c +++ b/usr/src/uts/common/inet/ip/igmp.c @@ -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 @@ igmp_sendpkt(ilm_t *ilm, uchar_t type, ipaddr_t addr) 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 @@ igmp_sendpkt(ilm_t *ilm, uchar_t type, ipaddr_t addr) 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 @@ igmpv3_sendrpt(ipif_t *ipif, mrec_t *reclist) 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 @@ nextpkt: 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) { diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index dafa141b2f..3c210f89d1 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -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 @@ struct listptr_s { 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,17 +440,30 @@ uint32_t (*cl_inet_ipident)(uint8_t protocol, sa_family_t addr_family, * 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 + * + * 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 * - * 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. + * Trusted Solaris scenarios + * + * igsa_lock -> gcgrp_rwlock -> gcgrp_lock + * igsa_lock -> gcdb_lock + * gcgrp_rwlock -> ire_lock + * gcgrp_rwlock -> gcdb_lock * * IPSEC notes : * @@ -700,9 +730,9 @@ static mblk_t *ip_snmp_get_mib2_virt_multi(queue_t *, mblk_t *); 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 @@ icmp_inbound(queue_t *q, mblk_t *mp, boolean_t broadcast, ill_t *ill, 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 @@ icmp_inbound(queue_t *q, mblk_t *mp, boolean_t broadcast, ill_t *ill, * 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 @@ icmp_inbound(queue_t *q, mblk_t *mp, boolean_t broadcast, ill_t *ill, } 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 @@ icmp_inbound(queue_t *q, mblk_t *mp, boolean_t broadcast, ill_t *ill, 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 @@ icmp_inbound_too_big(icmph_t *icmph, ipha_t *ipha) 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 @@ icmp_inbound_too_big(icmph_t *icmph, ipha_t *ipha) 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 @@ ipoptp_next(ipoptp_t *optp) } /* + * 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 @@ icmp_redirect(mblk_t *mp) 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 @@ icmp_redirect(mblk_t *mp) 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 @@ icmp_redirect(mblk_t *mp) 0, 0, (RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST), - &ulp_info); + &ulp_info, + NULL, + NULL); if (ire == NULL) { freemsg(mp); @@ -2986,7 +3124,7 @@ icmp_redirect(mblk_t *mp) * 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 @@ icmp_pkt(queue_t *q, mblk_t *mp, void *stuff, size_t len, 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 @@ icmp_pkt(queue_t *q, mblk_t *mp, void *stuff, size_t len, 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 @@ icmp_pkt(queue_t *q, mblk_t *mp, void *stuff, size_t len, * 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 @@ icmp_pkt_err_ok(mblk_t *mp) 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 @@ icmp_pkt_err_ok(mblk_t *mp) 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 @@ ip_arp_news(queue_t *q, mblk_t *mp) 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 @@ ip_arp_news(queue_t *q, mblk_t *mp) */ 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 @@ ip_bind_v4(queue_t *q, mblk_t *mp, conn_t *connp) 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 @@ bad_addr: * 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 @@ ip_bind_laddr(conn_t *connp, mblk_t *mp, ipaddr_t src_addr, uint16_t lport, 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 @@ ip_bind_laddr(conn_t *connp, mblk_t *mp, ipaddr_t src_addr, uint16_t lport, */ 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 @@ ip_bind_laddr(conn_t *connp, mblk_t *mp, ipaddr_t src_addr, uint16_t lport, */ 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 @@ done: } } 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 @@ bad_addr: * 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, * 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 @@ ip_bind_connected(conn_t *connp, mblk_t *mp, ipaddr_t *src_addrp, */ 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 @@ ip_quiesce_conn(conn_t *connp) 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 @@ ip_close(queue_t *q, int flags) 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 @@ ip_csum_hdr(ipha_t *ipha) void ip_ddi_destroy(void) { + tnet_fini(); tcp_ddi_destroy(); sctp_ddi_destroy(); ipsec_loader_destroy(); @@ -5088,8 +5311,8 @@ ip_ddi_init(void) ip_kstat_init(); ip6_kstat_init(); icmp_kstat_init(); - ipsec_loader_start(); + tnet_init(); } /* @@ -5299,30 +5522,6 @@ ip_fanout_send_icmp(queue_t *q, mblk_t *mp, uint_t flags, 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 @@ ip_fanout_proto(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, uint_t flags, 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 @@ ip_fanout_proto(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, uint_t flags, 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 @@ ip_fanout_proto(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, uint_t flags, 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 @@ ip_fanout_tcp(queue_t *q, mblk_t *mp, ill_t *recv_ill, ipha_t *ipha, 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 @@ ip_fanout_udp(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, ipaddr_t src; zoneid_t last_zoneid; boolean_t reuseaddr; + boolean_t shared_addr; first_mp = mp; if (mctl_present) { @@ -5974,6 +6193,13 @@ ip_fanout_udp(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, 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 @@ ip_fanout_udp(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, 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 @@ ip_fanout_udp(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, 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 @@ ip_fanout_udp(queue_t *q, mblk_t *mp, ill_t *ill, ipha_t *ipha, 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 @@ notfound: 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 @@ notfound: } 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 @@ notfound: 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 @@ notfound: 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 @@ ip_massage_options(ipha_t *ipha) * 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) * 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) (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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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,13 +7968,22 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) 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); + if (gcgrp != NULL) { + GCGRP_REFRELE(gcgrp); + gcgrp = NULL; + } break; } + /* reference now held by IRE */ + gcgrp = NULL; + if ((sire != NULL) && (sire->ire_flags & RTF_MULTIRT)) { copy_mp = copymsg(first_mp); @@ -8065,7 +8391,8 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, (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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, */ 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, (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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, */ 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 @@ ip_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) *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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, * 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, * 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, * 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, * 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ ip_fill_mtuinfo(struct in6_addr *in6, in_port_t port, 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 @@ fragmented: 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 @@ find_sctp_client: 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 @@ ip_rput_process_forward(queue_t *q, mblk_t *mp, ire_t *ire, ipha_t *ipha, 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 @@ ip_rput_process_broadcast(queue_t **qp, mblk_t *mp, ire_t **irep, ipha_t *ipha, 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 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, size_t hdrlen) 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 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, size_t hdrlen) } } - 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 @@ ip_rput_forward(ire_t *ire, ipha_t *ipha, mblk_t *mp, ill_t *in_ill) /* 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 @@ ip_rput_forward_multicast(ipaddr_t dst, mblk_t *mp, ipif_t *ipif) */ 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 @@ ip_rput_forward_options(mblk_t *mp, ipha_t *ipha, ire_t *ire) } 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 @@ ip_rput_forward_options(mblk_t *mp, ipha_t *ipha, ire_t *ire) * 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 @@ ip_rput_forward_options(mblk_t *mp, ipha_t *ipha, ire_t *ire) 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 @@ ip_fanout_proto_again(mblk_t *ipsec_mp, ill_t *ill, ill_t *recv_ill, ire_t *ire) } 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 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire, 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 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire, 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 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire, 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 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire, 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 @@ ip_rput_local_options(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire) 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 @@ ip_rput_options(queue_t *q, mblk_t *mp, ipha_t *ipha, ipaddr_t *dstp) 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 @@ ip_rput_options(queue_t *q, mblk_t *mp, ipha_t *ipha, ipaddr_t *dstp) * 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 @@ ip_rput_options(queue_t *q, mblk_t *mp, ipha_t *ipha, ipaddr_t *dstp) 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 @@ bad_src_route: * - 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 @@ bad_src_route: * - 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 @@ bad_src_route: * * 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 @@ ip_snmp_get_mib2_ip(queue_t *q, mblk_t *mpctl) 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 @@ ip_snmp_get_mib2_ip_addr(queue_t *q, mblk_t *mpctl) 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 @@ ip_snmp_get_mib2_ip6_addr(queue_t *q, mblk_t *mpctl) 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 @@ ip_snmp_get_mib2_ip_group_mem(queue_t *q, mblk_t *mpctl) 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 @@ ip_snmp_get_mib2_multi_rtable(queue_t *q, mblk_t *mpctl) } /* - * 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; + struct opthdr *optp; + mblk_t *mp2ctl; /* Returned */ + mblk_t *mp3ctl; /* nettomedia */ + mblk_t *mp4ctl; /* routeattrs */ + iproutedata_t ird; + zoneid_t zoneid; /* - * make a copy of the original message + * 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 @@ ip_snmp_get_mib2_ip_route_media(queue_t *q, mblk_t *mpctl) 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; + struct opthdr *optp; + mblk_t *mp2ctl; /* Returned */ + mblk_t *mp3ctl; /* nettomedia */ + mblk_t *mp4ctl; /* routeattrs */ + iproutedata_t ird; + zoneid_t zoneid; /* - * make a copy of the original message + * 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 @@ ip_snmp_get_mib2_icmp6(queue_t *q, mblk_t *mpctl) * 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->ipRouteIfIndex.o_length = + mi_strlen(re->ipRouteIfIndex.o_bytes); } - re.ipRouteMetric1 = -1; - re.ipRouteMetric2 = -1; - re.ipRouteMetric3 = -1; - re.ipRouteMetric4 = -1; + 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_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))); + } + + 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; } - 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))) { + + 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", - (uint_t)sizeof (re))); + (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 @@ ip_snmp_get2_v4(ire_t *ire, listptr_t re_ntme[]) 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))); } +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. + * ire_walk routine to create ipv6RouteEntryTable and ipRouteEntryTable. */ static void -ip_snmp_get2_v6_route(ire_t *ire, listptr_t *re_ntme) +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 @@ ip_snmp_get2_v6_route(ire_t *ire, listptr_t *re_ntme) 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 @@ ip_snmp_get2_v6_media(nce_t *nce, listptr_t *re_ntme) 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 @@ ip_source_routed(ipha_t *ipha) * 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 @@ ip_unbind(queue_t *q, mblk_t *mp) 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 @@ ip_output(void *arg, mblk_t *mp, void *arg2, int caller) 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 @@ ip_output(void *arg, mblk_t *mp, void *arg2, int caller) 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 @@ ip_output(void *arg, mblk_t *mp, void *arg2, int caller) 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 @@ ip_output(void *arg, mblk_t *mp, void *arg2, int caller) * 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 @@ standard_path: */ 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 @@ standard_path: * 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 @@ standard_path: 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 @@ standard_path: * 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 @@ qnext: 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 @@ qnext: 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 @@ qnext: } 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 @@ qnext: 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 @@ qnext: 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 @@ qnext: } } } 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 @@ send_from_ill: 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 @@ send_from_ill: 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 @@ send_from_ill: match_flags = MATCH_IRE_MARK_PRIVATE_ADDR | MATCH_IRE_GW; ire = ire_ctable_lookup(dst, nexthop_addr, 0, - NULL, zoneid, match_flags); + NULL, zoneid, MBLK_GETLABEL(mp), match_flags); } else { - ire = ire_cache_lookup(dst, zoneid); + ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp)); } if (!ire) { /* @@ -19121,7 +19763,8 @@ noirefound: * 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 @@ noirefound: 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 @@ ip_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller) } } - 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_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller) * 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 @@ another:; 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 @@ broadcast: } } - noprepend: ASSERT(ipsec_len == 0); mp1 = ip_wput_attach_llhdr(mp, ire, IPP_LOCAL_OUT, ill_index); @@ -21619,6 +22272,8 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, "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 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, 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 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, 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 @@ ip_wput_local(queue_t *q, ill_t *ill, ipha_t *ipha, mblk_t *mp, ire_t *ire, 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 @@ ip_wput_local_options(ipha_t *ipha) 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 @@ ip_wput_multicast(queue_t *q, mblk_t *mp, ipif_t *ipif) * 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 @@ ip_wput_attach_llhdr(mblk_t *mp, ire_t *ire, ip_proc_t proc, uint32_t ill_index) 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_err: } 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 @@ ip_wput_ipsec_out_v6(queue_t *q, mblk_t *ipsec_mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_wput_ipsec_out_v6(queue_t *q, mblk_t *ipsec_mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_wput_ipsec_out_v6(queue_t *q, mblk_t *ipsec_mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_wput_ipsec_out(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, ill_t *ill, 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 @@ ip_wput_ipsec_out(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, ill_t *ill, * 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 @@ ip_wput_ipsec_out(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, ill_t *ill, * 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 @@ ip_wput_ipsec_out(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, ill_t *ill, } 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 @@ nak: 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 @@ ip_wput_options(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, 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 @@ conn_wantpacket(conn_t *connp, ill_t *ill, ipha_t *ipha, int fanout_flags, 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 @@ ip_multirt_apply_membership(int (*fn)(conn_t *, boolean_t, ipaddr_t, ipaddr_t, 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 @@ ip_fanout_sctp_raw(mblk_t *mp, ill_t *recv_ill, ipha_t *ipha, boolean_t isv4, } 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 @@ ip_no_forward(ipha_t *ipha, ill_t *ill) 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 @@ ip_loopback_src_or_dst(ipha_t *ipha, ill_t *ill) } 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); +} diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c index 72783626ad..c39242bc07 100644 --- a/usr/src/uts/common/inet/ip/ip6.c +++ b/usr/src/uts/common/inet/ip/ip6.c @@ -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 @@ static kstat_t *ip6_kstat; 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 @@ icmp_inbound_v6(queue_t *q, mblk_t *mp, ill_t *ill, uint_t hdr_length, 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 @@ icmp_inbound_v6(queue_t *q, mblk_t *mp, ill_t *ill, uint_t hdr_length, * 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 @@ icmp_inbound_v6(queue_t *q, mblk_t *mp, ill_t *ill, uint_t hdr_length, 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 @@ icmp_inbound_too_big_v6(queue_t *q, mblk_t *mp, ill_t *ill, 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 @@ icmp_inbound_too_big_v6(queue_t *q, mblk_t *mp, ill_t *ill, * 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 @@ icmp_redirect_ok_v6(ill_t *ill, mblk_t *mp) * 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 @@ icmp_redirect_v6(queue_t *q, mblk_t *mp, ill_t *ill) 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 @@ icmp_redirect_v6(queue_t *q, mblk_t *mp, ill_t *ill) 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 @@ icmp_redirect_v6(queue_t *q, mblk_t *mp, ill_t *ill) 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 @@ icmp_redirect_v6(queue_t *q, mblk_t *mp, ill_t *ill) 0, 0, 0, - &ulp_info); + &ulp_info, + NULL, + NULL); } if (ire == NULL) goto fail_redirect; @@ -1450,7 +1481,7 @@ icmp_redirect_v6(queue_t *q, mblk_t *mp, ill_t *ill) * 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 @@ icmp_pick_source_v6(queue_t *wq, in6_addr_t *origsrc, in6_addr_t *origdst, } 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 @@ icmp_pick_source_v6(queue_t *wq, in6_addr_t *origsrc, in6_addr_t *origdst, 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 @@ icmp_pick_source_v6(queue_t *wq, in6_addr_t *origsrc, in6_addr_t *origdst, * 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 @@ ip_bind_v6(queue_t *q, mblk_t *mp, conn_t *connp, ip6_pkt_t *ipp) 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 @@ ip_bind_laddr_v6(conn_t *connp, mblk_t *mp, const in6_addr_t *v6src, 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 @@ ip_bind_laddr_v6(conn_t *connp, mblk_t *mp, const in6_addr_t *v6src, * 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 @@ ip_bind_laddr_v6(conn_t *connp, mblk_t *mp, const in6_addr_t *v6src, 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 @@ ip_bind_laddr_v6(conn_t *connp, mblk_t *mp, const in6_addr_t *v6src, } } 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 @@ ip_bind_connected_v6(conn_t *connp, mblk_t *mp, in6_addr_t *v6src, 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 @@ ip_bind_connected_v6(conn_t *connp, mblk_t *mp, in6_addr_t *v6src, } /* + * 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 @@ ip_bind_connected_v6(conn_t *connp, mblk_t *mp, in6_addr_t *v6src, 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 @@ ip_bind_connected_v6(conn_t *connp, mblk_t *mp, in6_addr_t *v6src, 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 @@ ip_bind_connected_v6(conn_t *connp, mblk_t *mp, in6_addr_t *v6src, * 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 @@ ip_fanout_proto_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_fanout_proto_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_fanout_proto_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, ill_t *ill, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, 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 @@ ip_fanout_udp_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, uint32_t ports, /* 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, * 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, * 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, } 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, (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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, * 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_v6(queue_t *q, mblk_t *mp, const in6_addr_t *v6dstp, 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 @@ ip_newroute_ipif_v6(queue_t *q, mblk_t *mp, ipif_t *ipif, (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 @@ ip_newroute_ipif_v6(queue_t *q, mblk_t *mp, ipif_t *ipif, */ 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 @@ ip_newroute_ipif_v6(queue_t *q, mblk_t *mp, ipif_t *ipif, (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 @@ ip_newroute_ipif_v6(queue_t *q, mblk_t *mp, ipif_t *ipif, */ 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 @@ ip_newroute_ipif_v6(queue_t *q, mblk_t *mp, ipif_t *ipif, */ 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 @@ ip_process_options_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, 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 @@ ip_process_options_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, } 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 @@ ip_process_options_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, 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 @@ ip_process_options_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h, (uint8_t *)ip6h), B_FALSE, B_TRUE); return (-1); + default: + ASSERT(0); } } } @@ -7014,6 +7238,18 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, } /* + * 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 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, */ 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 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, */ 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 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, 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 @@ tcp_fanout: } 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 @@ ip_source_routed_v6(ip6_t *ip6h, mblk_t *mp) 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 @@ ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller) 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 @@ ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller) * 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 @@ ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller) 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 @@ ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller) * 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 @@ send_from_ill: * 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 @@ send_from_ill: * 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 @@ ip_wput_ire_v6(queue_t *q, mblk_t *mp, ire_t *ire, int unspec_src, 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_wput_ire_v6(queue_t *q, mblk_t *mp, ire_t *ire, int unspec_src, * 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 @@ conn_wantpacket_v6(conn_t *connp, ill_t *ill, ip6_t *ip6h, int fanout_flags, * 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 @@ conn_wantpacket_v6(conn_t *connp, ill_t *ill, ip6_t *ip6h, int fanout_flags, } 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 @@ ip_multirt_apply_membership_v6(int (*fn)(conn_t *, boolean_t, 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 @@ ip6_set_pktinfo(cred_t *cr, conn_t *connp, struct in6_pktinfo *pkti, mblk_t *mp) 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 diff --git a/usr/src/uts/common/inet/ip/ip6_if.c b/usr/src/uts/common/inet/ip/ip6_if.c index 46fe66e74d..92ad9ae7ca 100644 --- a/usr/src/uts/common/inet/ip/ip6_if.c +++ b/usr/src/uts/common/inet/ip/ip6_if.c @@ -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 @@ repeat: 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 @@ ip_remote_addr_ok_v6(const in6_addr_t *addr, const in6_addr_t *subnet_mask) 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, */ 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 0, 0, flags, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (ire == NULL) { if (ipif_refheld) ipif_refrele(ipif); @@ -551,7 +559,7 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, /* 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, } } + /* + * 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 @@ ip_rt_delete_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ip_rt_delete_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 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 @@ ipif_recover_ire_v6(ipif_t *ipif) 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 @@ typedef struct candidate { #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 @@ rule_prefix(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo) } /* + * 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 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, 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 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, rule_label, rule_temporary, rule_prefix, + rule_zone_specific, NULL }; @@ -1868,6 +1952,26 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, 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 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, 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 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, 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 @@ ipif_recreate_interface_routes_v6(ipif_t *old_ipif, ipif_t *ipif) 0, 0, 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (ire != NULL) { ire_t *ret_ire; @@ -2505,6 +2642,22 @@ ipif_up_done_v6(ipif_t *ipif) 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 @@ ipif_up_done_v6(ipif_t *ipif) 0, 0, (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE : 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); } /* @@ -2581,7 +2736,9 @@ ipif_up_done_v6(ipif_t *ipif) 0, 0, (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE : 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); } /* @@ -2608,7 +2765,7 @@ ipif_up_done_v6(ipif_t *ipif) * 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 @@ ipif_up_done_v6(ipif_t *ipif) 0, 0, RTF_UP, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); } else { ire_refrele(isdup); } diff --git a/usr/src/uts/common/inet/ip/ip6_ire.c b/usr/src/uts/common/inet/ip/ip6_ire.c index 598c6da3f3..458cf296d2 100644 --- a/usr/src/uts/common/inet/ip/ip6_ire.c +++ b/usr/src/uts/common/inet/ip/ip6_ire.c @@ -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 ire_t *ire_ihandle_lookup_onlink_v6(ire_t *cire); 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 @@ ire_init_v6(ire_t *ire, const in6_addr_t *v6addr, 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_init_v6(ire_t *ire, const in6_addr_t *v6addr, 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 @@ ire_create_mp_v6(const in6_addr_t *v6addr, const in6_addr_t *v6mask, 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 @@ ire_create_mp_v6(const in6_addr_t *v6addr, const in6_addr_t *v6mask, 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 @@ ire_create_v6(const in6_addr_t *v6addr, const in6_addr_t *v6mask, 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 @@ ire_create_v6(const in6_addr_t *v6addr, const in6_addr_t *v6mask, 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 @@ ire_lookup_multi_v6(const in6_addr_t *group, zoneid_t zoneid) 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 @@ ire_lookup_multi_v6(const in6_addr_t *group, zoneid_t zoneid) * 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_lookup_multi_v6(const in6_addr_t *group, zoneid_t zoneid) 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 @@ ire_lookup_local_v6(zoneid_t zoneid) 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 @@ ire_add_v6(ire_t **ire_p, queue_t *q, mblk_t *mp, ipsq_func_t func) 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 @@ failed: 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 @@ ire_flush_cache_v6(ire_t *ire, int flag) */ 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_match_args_v6(ire_t *ire, const in6_addr_t *addr, const in6_addr_t *mask, (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 @@ ire_match_args_v6(ire_t *ire, const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_match_args_v6(ire_t *ire, const in6_addr_t *addr, const in6_addr_t *mask, ((!(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_match_args_v6(ire_t *ire, const in6_addr_t *addr, const in6_addr_t *mask, */ 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 @@ ire_route_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, */ 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_route_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, */ 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, */ 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 @@ ire_ftable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *mask, 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 @@ found_ire_held: * 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 @@ found_ire_held: 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 @@ found_ire_held: 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 @@ found_ire_held: } /* + * 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 @@ found_ire_held: */ 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 @@ ire_ctable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *gateway, 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 @@ ire_ctable_lookup_v6(const in6_addr_t *addr, const in6_addr_t *gateway, * 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 @@ ire_cache_lookup_v6(const in6_addr_t *addr, zoneid_t zoneid) 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_ihandle_lookup_onlink_v6(ire_t *cire) */ 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_ihandle_lookup_offlink_v6(ire_t *cire, ire_t *pire) */ 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 @@ ire_ihandle_lookup_offlink_v6(ire_t *cire, ire_t *pire) 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 @@ ire_ihandle_lookup_offlink_v6(ire_t *cire, ire_t *pire) 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 @@ ire_ihandle_lookup_offlink_v6(ire_t *cire, ire_t *pire) * (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 @@ ipif_to_ire_v6(ipif_t *ipif) * 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 @@ ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp) /* 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 @@ ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp) 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 @@ ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp) /* 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 @@ ire_multirt_need_resolve_v6(const in6_addr_t *v6dstp) * 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 @@ ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) * 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 @@ ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) (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 @@ ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) * 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 @@ ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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 @@ ire_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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_multirt_lookup_v6(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) (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 @@ ipif_lookup_multi_ire_v6(ipif_t *ipif, const in6_addr_t *v6dstp) 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 @@ ipif_lookup_multi_ire_v6(ipif_t *ipif, const in6_addr_t *v6dstp) 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 @@ ipif_lookup_multi_ire_v6(ipif_t *ipif, const in6_addr_t *v6dstp) 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) { diff --git a/usr/src/uts/common/inet/ip/ip6_rts.c b/usr/src/uts/common/inet/ip/ip6_rts.c index 427f600d69..0fa31914f6 100644 --- a/usr/src/uts/common/inet/ip/ip6_rts.c +++ b/usr/src/uts/common/inet/ip/ip6_rts.c @@ -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 @@ void 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 @@ rts_fill_msg_v6(int type, int rtm_addrs, const in6_addr_t *dst, int i; ASSERT(mp != NULL); + ASSERT(sacnt == 0 || gc != NULL); /* * First find the type of the message * and its length. @@ -98,7 +102,7 @@ rts_fill_msg_v6(int type, int rtm_addrs, const in6_addr_t *dst, * 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 @@ rts_fill_msg_v6(int type, int rtm_addrs, const in6_addr_t *dst, 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 @@ ip_rts_change_v6(int type, const in6_addr_t *dst_addr, 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; diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 12d77d80b3..c0bb78caaa 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -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 @@ ill_init(queue_t *q, ill_t *ill) * 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 @@ ip_ipif_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) 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 @@ repeat: 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 @@ ipif_lookup_remote(ill_t *ill, ipaddr_t addr, zoneid_t zoneid) 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 @@ ipif_lookup_remote(ill_t *ill, ipaddr_t addr, zoneid_t zoneid) } 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 @@ int 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, } 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 0, 0, flags, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (ire == NULL) { if (ipif_refheld) ipif_refrele(ipif); @@ -6437,7 +6454,7 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, /* 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, * 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, } } + /* + * 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 @@ ip_rt_delete(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, } 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 @@ ip_rt_delete(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr, 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 @@ ip_siocaddrt(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_get_numifs(zoneid_t zoneid) 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 @@ ip_get_numlifs(int family, int lifn_flags, zoneid_t zoneid) continue; if (zoneid != ipif->ipif_zoneid && + ipif->ipif_zoneid != ALL_ZONES && (zoneid != GLOBAL_ZONEID || !(lifn_flags & LIFC_ALLZONES))) continue; @@ -8027,7 +8101,8 @@ ip_sioctl_get_ifconf(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, 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 @@ ip_sioctl_get_lifconf(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, continue; if (zoneid != ipif->ipif_zoneid && + ipif->ipif_zoneid != ALL_ZONES && (zoneid != GLOBAL_ZONEID || !(flags & LIFC_ALLZONES))) continue; @@ -8529,10 +8605,10 @@ ip_sioctl_dstinfo(queue_t *q, mblk_t *mp) 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 @@ ip_sioctl_tmyaddr(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_tmyaddr(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_tonlink(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_tonlink(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_tonlink(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_xarp(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, * 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 @@ ip_sioctl_xarp(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_arp(ipif_t *dummy_ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, * 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 @@ ip_sioctl_iocack(queue_t *q, mblk_t *mp) 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 @@ ip_sioctl_brdaddr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, * 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 @@ ill_bcast_delete_and_add(ill_t *ill, ipaddr_t addr) */ 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 @@ ill_bcast_delete_and_add(ill_t *ill, ipaddr_t addr) 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 @@ ill_clear_bcast_mark(ill_t *ill, ipaddr_t addr) 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 @@ ill_mark_bcast(ill_group_t *illgrp, ipaddr_t addr) 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 @@ redo: 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 @@ redo: 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 @@ ipif_free_tail(ipif_t *ipif) * "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 @@ ipif_lookup_on_name(char *name, size_t namelen, boolean_t do_alloc, 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 @@ ipif_recover_ire(ipif_t *ipif) 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 @@ ip_addr_availability_check(ipif_t *new_ipif) 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 @@ ipif_up_done(ipif_t *ipif) /* 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 @@ ipif_up_done(ipif_t *ipif) 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 @@ ipif_up_done(ipif_t *ipif) 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 @@ ipif_up_done(ipif_t *ipif) 0, 0, (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE: 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); } /* @@ -19239,7 +19343,7 @@ ipif_up_done(ipif_t *ipif) 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 @@ ipif_select_source(ill_t *ill, ipaddr_t dst, zoneid_t zoneid) 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 @@ ipif_select_source(ill_t *ill, ipaddr_t dst, zoneid_t zoneid) } /* + * 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 @@ retry: * 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 @@ retry: 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 @@ retry: */ 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 @@ retry: } 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 @@ retry: wrapped = B_TRUE; index = 0; } - if (ipif_same_found == B_TRUE) + if (ipif_same_found) break; } } @@ -19763,6 +19932,8 @@ retry: 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 @@ ipif_recreate_interface_routes(ipif_t *old_ipif, ipif_t *ipif) 0, 0, 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (ire != NULL) { ire_t *ret_ire; @@ -20086,10 +20259,10 @@ ipif_check_bcast_ires(ipif_t *test_ipif) 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 @@ ipif_check_bcast_ires(ipif_t *test_ipif) */ 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_lookup_on_ifindex(uint_t index, boolean_t isv6, zoneid_t zoneid, 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 @@ ip_sioctl_slifzone(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_slifzone(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_slifzone_restart(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, 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 @@ ip_sioctl_slifzone_restart(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, 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 @@ ip_mrtun_rt_add(ipaddr_t in_src_addr, int flags, ipif_t *ipif_arg, 0, 0, flags, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (ire == NULL) return (ENOMEM); @@ -21977,7 +22159,8 @@ ipif_lookup_onlink_addr(ipaddr_t addr, zoneid_t zoneid) 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 @@ ip_cgtp_bcast_add(ire_t *ire, ire_t *ire_dst) 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 @@ ip_cgtp_bcast_add(ire_t *ire, ire_t *ire_dst) 0, 0, ire->ire_flags, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); if (bcast_ire != NULL) { @@ -22172,12 +22357,12 @@ ip_cgtp_bcast_delete(ire_t *ire) 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 @@ ip_cgtp_bcast_delete(ire_t *ire) 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 @@ ipif_lookup_zoneid(ill_t *ill, zoneid_t zoneid, int flags, ipif_t **ipifp) 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; diff --git a/usr/src/uts/common/inet/ip/ip_ire.c b/usr/src/uts/common/inet/ip/ip_ire.c index c1c903ff25..61973d25aa 100644 --- a/usr/src/uts/common/inet/ip/ip_ire.c +++ b/usr/src/uts/common/inet/ip/ip_ire.c @@ -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_ftable(ire_t *ire, char *mp); 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 @@ ip_ire_advise(queue_t *q, mblk_t *mp, cred_t *ioc_cr) /* 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 @@ ip_ire_delete(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ done: } /* 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 @@ ip_ire_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) 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 @@ ip_ire_report_mrtun(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) "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 @@ ip_ire_report_srcif(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *ioc_cr) "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 @@ ip_ire_req(queue_t *q, mblk_t *mp) */ 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 @@ ire_add_then_send(queue_t *q, ire_t *ire, mblk_t *mp) 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 @@ ire_add_then_send(queue_t *q, ire_t *ire, mblk_t *mp) 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 @@ ire_init(ire_t *ire, uchar_t *addr, uchar_t *mask, uchar_t *src_addr, 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 @@ ire_init(ire_t *ire, uchar_t *addr, uchar_t *mask, uchar_t *src_addr, 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 @@ ire_create_mp(uchar_t *addr, uchar_t *mask, uchar_t *src_addr, uchar_t *gateway, 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 @@ ire_create_mp(uchar_t *addr, uchar_t *mask, uchar_t *src_addr, uchar_t *gateway, 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 @@ ire_create(uchar_t *addr, uchar_t *mask, uchar_t *src_addr, 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) + const iulp_t *ulp_info, tsol_gc_t *gc, tsol_gcgrp_t *gcgrp) { ire_t *ire; ire_t *ret_ire; @@ -1803,7 +1812,7 @@ ire_create(uchar_t *addr, uchar_t *mask, uchar_t *src_addr, uchar_t *gateway, 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 @@ ire_create(uchar_t *addr, uchar_t *mask, uchar_t *src_addr, uchar_t *gateway, /* * 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 @@ ire_init_common(ire_t *ire, uint_t *max_fragp, mblk_t *fp_mp, #ifdef IRE_DEBUG bzero(ire->ire_trace, sizeof (th_trace_t *) * IP_TR_HASH_MAX); #endif + + return (B_TRUE); } /* @@ -1918,7 +1957,7 @@ ire_check_and_create_bcast(ipif_t *ipif, ipaddr_t addr, ire_t **irep, /* 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 @@ ire_create_bcast(ipif_t *ipif, ipaddr_t addr, ire_t **irep) 0, 0, 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); *irep++ = ire_create( (uchar_t *)&addr, /* dest address */ @@ -1996,7 +2037,9 @@ ire_create_bcast(ipif_t *ipif, ipaddr_t addr, ire_t **irep) 0, 0, 0, - &ire_uinfo_null); + &ire_uinfo_null, + NULL, + NULL); return (irep); } @@ -2120,7 +2163,7 @@ ire_fastpath_update(ire_t *ire, void *arg) 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 @@ ire_lookup_multi(ipaddr_t group, zoneid_t zoneid) 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 @@ ire_lookup_multi(ipaddr_t group, zoneid_t zoneid) * 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_lookup_multi(ipaddr_t group, zoneid_t zoneid) 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 @@ ire_lookup_local(zoneid_t zoneid) 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 @@ ire_lookup_local(zoneid_t zoneid) * 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 @@ ire_to_ill(ire_t *ire) /* 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 @@ ire_walk_v6(pfv_t func, char *arg, zoneid_t zoneid) * 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 @@ ire_walk_ipvers(pfv_t func, char *arg, uchar_t vers, zoneid_t zoneid) * 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 @@ ire_walk_ill_v4(uint_t match_flags, uint_t ire_type, pfv_t func, char *arg, } 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 @@ ire_walk_ill_v6(uint_t match_flags, uint_t ire_type, pfv_t func, char *arg, */ 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 @@ ire_walk_ill_match(uint_t match_flags, uint_t ire_type, ire_t *ire, * 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 @@ ire_walk_ill_match(uint_t match_flags, uint_t ire_type, ire_t *ire, } 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 @@ ire_walk_ill_match(uint_t match_flags, uint_t ire_type, ire_t *ire, 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 @@ ire_walk_ill_match(uint_t match_flags, uint_t ire_type, ire_t *ire, */ 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 @@ ire_walk_ill_tables(uint_t match_flags, uint_t ire_type, pfv_t func, * 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 @@ ire_add(ire_t **irep, queue_t *q, mblk_t *mp, ipsq_func_t func) &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 @@ ire_add_v4(ire_t **ire_p, queue_t *q, mblk_t *mp, ipsq_func_t func) 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 @@ ire_add_v4(ire_t **ire_p, queue_t *q, mblk_t *mp, ipsq_func_t func) 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 @@ end: 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 @@ ire_flush_cache_v4(ire_t *ire, int flag) */ 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_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, (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 @@ ire_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ ire_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, ((!(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_match_args(ire_t *ire, ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, */ 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 @@ ire_route_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, */ 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_route_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, */ 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 @@ ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ ire_ftable_lookup(ipaddr_t addr, ipaddr_t mask, ipaddr_t gateway, 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 @@ found_ire_held: * 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 @@ found_ire_held: 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 @@ found_ire_held: 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 @@ found_ire_held: } /* + * 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 @@ ire_ctable_lookup(ipaddr_t addr, ipaddr_t gateway, int type, ipif_t *ipif, 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 @@ ire_ctable_lookup(ipaddr_t addr, ipaddr_t gateway, int type, ipif_t *ipif, * 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 @@ ire_cache_lookup(ipaddr_t addr, zoneid_t zoneid) 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_ihandle_lookup_offlink(ire_t *cire, ire_t *pire) */ 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 @@ ire_ihandle_lookup_offlink(ire_t *cire, ire_t *pire) 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 @@ ire_ihandle_lookup_offlink(ire_t *cire, ire_t *pire) 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_ihandle_lookup_onlink(ire_t *cire) */ 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 @@ ire_mrtun_lookup(ipaddr_t srcaddr, ill_t *ill) * 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 @@ ire_srcif_table_lookup(ipaddr_t dst_addr, int ire_type, ipif_t *ipif, 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 @@ ire_add_srcif_v4(ire_t **ire_p, queue_t *q, mblk_t *mp, ipsq_func_t func) 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 @@ ire_update_srcif_v4(ire_t *ire) * 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 @@ ire_multirt_need_resolve(ipaddr_t dst) /* 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 @@ ire_multirt_need_resolve(ipaddr_t dst) 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 @@ ire_multirt_need_resolve(ipaddr_t dst) /* 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 @@ ire_multirt_need_resolve(ipaddr_t dst) * 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 @@ ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) * 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 @@ ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) (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 @@ ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) * 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 @@ ire_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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_multirt_lookup(ire_t **ire_arg, ire_t **fire_arg, uint32_t flags) 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 @@ ipif_lookup_multi_ire(ipif_t *ipif, ipaddr_t group) 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 @@ ipif_lookup_multi_ire(ipif_t *ipif, ipaddr_t group) 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 @@ ipif_lookup_multi_ire(ipif_t *ipif, ipaddr_t group) 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 @@ ip_nexthop_route(const struct sockaddr *target, char *ifname) 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 @@ ip_nexthop(const struct sockaddr *target, const char *ifname) 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)) { diff --git a/usr/src/uts/common/inet/ip/ip_mroute.c b/usr/src/uts/common/inet/ip/ip_mroute.c index 0f76762daa..91fe418366 100644 --- a/usr/src/uts/common/inet/ip/ip_mroute.c +++ b/usr/src/uts/common/inet/ip/ip_mroute.c @@ -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 @@ tbf_send_packet(struct vif *vifp, mblk_t *mp) } 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, diff --git a/usr/src/uts/common/inet/ip/ip_multi.c b/usr/src/uts/common/inet/ip/ip_multi.c index 0c42de575d..02498affa7 100644 --- a/usr/src/uts/common/inet/ip/ip_multi.c +++ b/usr/src/uts/common/inet/ip/ip_multi.c @@ -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 <net/if.h> -#include <net/if_arp.h> #include <sys/sockio.h> +#include <net/if.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_add_v6(ipif_t *ipif, const in6_addr_t *v6group, ilg_stat_t ilgstat, 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. diff --git a/usr/src/uts/common/inet/ip/ip_ndp.c b/usr/src/uts/common/inet/ip/ip_ndp.c index 0d661efb2d..c52881ca8d 100644 --- a/usr/src/uts/common/inet/ip/ip_ndp.c +++ b/usr/src/uts/common/inet/ip/ip_ndp.c @@ -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 @@ ndp_process(nce_t *nce, uchar_t *hw_addr, uint32_t flag, boolean_t is_adv) */ 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 @@ ndp_process(nce_t *nce, uchar_t *hw_addr, uint32_t flag, boolean_t is_adv) * 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 @@ ndp_walk_impl(ill_t *ill, pfi_t pfi, uchar_t *arg1, boolean_t trace) } 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 @@ ndp_prepend_zone(mblk_t *mp, zoneid_t zoneid) 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); diff --git a/usr/src/uts/common/inet/ip/ip_opt_data.c b/usr/src/uts/common/inet/ip/ip_opt_data.c index 5e98e73e63..6f9f7c0f0e 100644 --- a/usr/src/uts/common/inet/ip/ip_opt_data.c +++ b/usr/src/uts/common/inet/ip/ip_opt_data.c @@ -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 @@ opdes_t ip_opt_arr[] = { { 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 */ }, diff --git a/usr/src/uts/common/inet/ip/ip_rts.c b/usr/src/uts/common/inet/ip/ip_rts.c index 4db16478d5..9312ee37c2 100644 --- a/usr/src/uts/common/inet/ip/ip_rts.c +++ b/usr/src/uts/common/inet/ip/ip_rts.c @@ -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 @@ ip_rts_rtmsg(int type, ire_t *ire, int error) 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 @@ ip_rts_rtmsg(int type, ire_t *ire, int error) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) } 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) } } - 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) (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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) &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 @@ ip_rts_request(queue_t *q, mblk_t *mp, cred_t *ioc_cr) 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 @@ done: 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 @@ done: * 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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) 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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) 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_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) 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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) (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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) &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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) (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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) 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 @@ rts_rtmget(mblk_t *mp, ire_t *ire, ire_t *sire, sa_family_t af) * 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 @@ 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 *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 @@ rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_addrp, *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 @@ rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_addrp, 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 @@ rts_getaddrs(rt_msghdr_t *rtm, in6_addr_t *dst_addrp, in6_addr_t *gw_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) + 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 @@ rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, int i; ASSERT(mp != NULL); + ASSERT(sacnt == 0 || gc != NULL); /* * First find the type of the message * and its length. @@ -1381,7 +1533,7 @@ rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, * 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 @@ rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, 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 @@ rts_fill_msg(int type, int rtm_addrs, ipaddr_t dst, ipaddr_t mask, * 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 @@ rts_header_msg_size(int type) * 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 @@ rts_data_msg_size(int rtm_addrs, sa_family_t af) break; } } + if (sacnt > 0) + length += sizeof (rtm_ext_t) + TSOL_RTSECATTR_SIZE(sacnt); + return (length); } @@ -1538,11 +1719,11 @@ ip_rts_change(int type, ipaddr_t dst_addr, ipaddr_t gw_addr, ipaddr_t net_mask, 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 @@ ip_rts_change(int type, ipaddr_t dst_addr, ipaddr_t gw_addr, ipaddr_t net_mask, * 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 @@ ip_rts_ifmsg(ipif_t *ipif) 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 @@ ip_rts_ifmsg(ipif_t *ipif) * 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 @@ ip_rts_newaddrmsg(int cmd, int error, ipif_t *ipif) 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 @@ ip_rts_newaddrmsg(int cmd, int error, ipif_t *ipif) 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; diff --git a/usr/src/uts/common/inet/ip/ipclassifier.c b/usr/src/uts/common/inet/ip/ipclassifier.c index 005d5bc886..9983068c64 100644 --- a/usr/src/uts/common/inet/ip/ipclassifier.c +++ b/usr/src/uts/common/inet/ip/ipclassifier.c @@ -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 @@ const char ipclassifier_version[] = "@(#)ipclassifier.c 1.6 04/03/31 SMI"; * 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 @@ const char ipclassifier_version[] = "@(#)ipclassifier.c 1.6 04/03/31 SMI"; * 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 @@ const char ipclassifier_version[] = "@(#)ipclassifier.c 1.6 04/03/31 SMI"; #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 @@ const char ipclassifier_version[] = "@(#)ipclassifier.c 1.6 04/03/31 SMI"; #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 @@ ipcl_conn_destroy(conn_t *connp) 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 @@ ipcl_conn_destroy(conn_t *connp) 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 @@ ipcl_hash_remove_locked(conn_t *connp, connf_t *connfp) 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 @@ ipcl_proto_insert(conn_t *connp, uint8_t protocol) 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 @@ ipcl_proto_insert_v6(conn_t *connp, uint8_t protocol) 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 @@ ipcl_sctp_hash_insert(conn_t *connp, in_port_t lport) } /* + * 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 @@ ipcl_bind_insert(conn_t *connp, uint8_t protocol, ipaddr_t src, uint16_t lport) connp->conn_lport = lport; switch (protocol) { - case IPPROTO_UDP: default: + if (is_system_labeled() && check_exempt_conflict_v4(connp)) + return (EADDRINUSE); + /* FALLTHROUGH */ + case IPPROTO_UDP: if (protocol == IPPROTO_UDP) { IPCL_DEBUG_LVL(64, ("ipcl_bind_insert: connp %p - udp\n", @@ -891,6 +1000,7 @@ ipcl_bind_insert(conn_t *connp, uint8_t protocol, ipaddr_t src, uint16_t lport) 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 @@ ipcl_bind_insert_v6(conn_t *connp, uint8_t protocol, const in6_addr_t *src, connp->conn_lport = lport; switch (protocol) { - case IPPROTO_UDP: default: + if (is_system_labeled() && check_exempt_conflict_v6(connp)) + return (EADDRINUSE); + /* FALLTHROUGH */ + case IPPROTO_UDP: if (protocol == IPPROTO_UDP) { IPCL_DEBUG_LVL(128, ("ipcl_bind_insert_v6: connp %p - udp\n", @@ -954,6 +1067,7 @@ ipcl_bind_insert_v6(conn_t *connp, uint8_t protocol, const in6_addr_t *src, /* 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 @@ ipcl_conn_insert(conn_t *connp, uint8_t protocol, ipaddr_t src, ret = ipcl_sctp_hash_insert(connp, lport); break; - case IPPROTO_UDP: 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: up = (uint16_t *)&ports; IPCL_CONN_INIT(connp, protocol, src, rem, ports); if (protocol == IPPROTO_UDP) { @@ -1128,8 +1252,11 @@ ipcl_conn_insert_v6(conn_t *connp, uint8_t protocol, const in6_addr_t *src, ret = ipcl_sctp_hash_insert(connp, lport); break; - case IPPROTO_UDP: default: + if (is_system_labeled() && check_exempt_conflict_v6(connp)) + return (EADDRINUSE); + /* FALLTHROUGH */ + case IPPROTO_UDP: up = (uint16_t *)&ports; IPCL_CONN_INIT_V6(connp, protocol, *src, *rem, ports); if (protocol == IPPROTO_UDP) { @@ -1155,6 +1282,11 @@ ipcl_conn_insert_v6(conn_t *connp, uint8_t protocol, const in6_addr_t *src, * 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 @@ ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) } 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 @@ ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v4(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) } 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) 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 @@ ipcl_classify_v6(mblk_t *mp, uint8_t protocol, uint_t hdr_len, zoneid_t zoneid) break; } - return (NULL); } @@ -1384,52 +1681,96 @@ ipcl_classify(mblk_t *mp, zoneid_t zoneid) } 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 @@ ipcl_tcp_lookup_reversed_ipv6(ip6_t *ip6h, tcpha_t *tcpha, int min_state, } /* - * 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 @@ ipcl_lookup_listener_v4(uint16_t lport, ipaddr_t laddr, zoneid_t zoneid) 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 @@ ipcl_lookup_listener_v4(uint16_t lport, ipaddr_t laddr, zoneid_t zoneid) 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 @@ ipcl_lookup_listener_v6(uint16_t lport, in6_addr_t *laddr, uint_t ifindex, 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); diff --git a/usr/src/uts/common/inet/ip/ipsecah.c b/usr/src/uts/common/inet/ip/ipsecah.c index 13f0a175c2..1c7ceca581 100644 --- a/usr/src/uts/common/inet/ip/ipsecah.c +++ b/usr/src/uts/common/inet/ip/ipsecah.c @@ -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 @@ ah_auth_in_done(mblk_t *ipsec_in) 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 @@ ah_auth_out_done(mblk_t *ipsec_out) 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) { diff --git a/usr/src/uts/common/inet/ip/nattymod.c b/usr/src/uts/common/inet/ip/nattymod.c index f98e816872..b73919818b 100644 --- a/usr/src/uts/common/inet/ip/nattymod.c +++ b/usr/src/uts/common/inet/ip/nattymod.c @@ -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 @@ get_my_ire(nattyinfo_t *ni, ipaddr_t addr) 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; diff --git a/usr/src/uts/common/inet/ip/spd.c b/usr/src/uts/common/inet/ip/spd.c index 4e420a45c4..0c7987ba70 100644 --- a/usr/src/uts/common/inet/ip/spd.c +++ b/usr/src/uts/common/inet/ip/spd.c @@ -3471,6 +3471,7 @@ ipsec_in_to_out(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h) 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 @@ ip_wput_attach_policy(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h, ire_t *ire, * 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); } diff --git a/usr/src/uts/common/inet/ip/tn_ipopt.c b/usr/src/uts/common/inet/ip/tn_ipopt.c new file mode 100644 index 0000000000..2b96c7f544 --- /dev/null +++ b/usr/src/uts/common/inet/ip/tn_ipopt.c @@ -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); +} diff --git a/usr/src/uts/common/inet/ip/tnet.c b/usr/src/uts/common/inet/ip/tnet.c new file mode 100644 index 0000000000..7abf751853 --- /dev/null +++ b/usr/src/uts/common/inet/ip/tnet.c @@ -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); +} diff --git a/usr/src/uts/common/inet/ip6.h b/usr/src/uts/common/inet/ip6.h index 8283250d2a..beae955d27 100644 --- a/usr/src/uts/common/inet/ip6.h +++ b/usr/src/uts/common/inet/ip6.h @@ -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 void convert2ascii(char *buf, const in6_addr_t *addr); 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 void ip_wput_ipsec_out_v6(queue_t *, mblk_t *, ip6_t *, ill_t *, 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 mld_timeout_start(int); 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); diff --git a/usr/src/uts/common/inet/ip_if.h b/usr/src/uts/common/inet/ip_if.h index dee83aa97e..a15b2c16eb 100644 --- a/usr/src/uts/common/inet/ip_if.h +++ b/usr/src/uts/common/inet/ip_if.h @@ -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_ipif_cache_delete(ire_t *, char *); 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 void ill_group_cleanup(ill_t *); 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_addr_availability_check(ipif_t *new_ipif); 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 *); diff --git a/usr/src/uts/common/inet/ip_ire.h b/usr/src/uts/common/inet/ip_ire.h index 2e4a3b99db..ee8cc01106 100644 --- a/usr/src/uts/common/inet/ip_ire.h +++ b/usr/src/uts/common/inet/ip_ire.h @@ -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 @@ extern "C" { /* 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_mrtun_count; 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 void ip_ire_req(queue_t *, mblk_t *); 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 int ire_atomic_start(irb_t *irb_ptr, ire_t *ire, queue_t *q, 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_create_bcast(ipif_t *, ipaddr_t, ire_t **); 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 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, ipif_t *, - zoneid_t, int); +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 boolean_t ire_fastpath_update(ire_t *, void *); 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 ire_t *ire_mrtun_lookup(ipaddr_t, ill_t *); 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 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 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, + 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 *); diff --git a/usr/src/uts/common/inet/ip_ndp.h b/usr/src/uts/common/inet/ip_ndp.h index 0f3855ba03..e31dd33801 100644 --- a/usr/src/uts/common/inet/ip_ndp.h +++ b/usr/src/uts/common/inet/ip_ndp.h @@ -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_resolver(ill_t *, const in6_addr_t *, mblk_t *, zoneid_t); 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 **); diff --git a/usr/src/uts/common/inet/ip_rts.h b/usr/src/uts/common/inet/ip_rts.h index 07445da7fd..8a8d6d1add 100644 --- a/usr/src/uts/common/inet/ip_rts.h +++ b/usr/src/uts/common/inet/ip_rts.h @@ -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(int, ipaddr_t, ipaddr_t, 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); diff --git a/usr/src/uts/common/inet/ipclassifier.h b/usr/src/uts/common/inet/ipclassifier.h index 09816fbec6..e11e1caf77 100644 --- a/usr/src/uts/common/inet/ipclassifier.h +++ b/usr/src/uts/common/inet/ipclassifier.h @@ -137,30 +137,32 @@ struct conn_s { 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_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_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_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_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 @@ struct conn_s { */ 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 @@ struct conn_s { 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 @@ struct conn_s { #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 @@ struct connf_s { (((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 @@ void ipcl_proto_insert_v6(conn_t *, uint8_t); 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 *); diff --git a/usr/src/uts/common/inet/mib2.h b/usr/src/uts/common/inet/mib2.h index 05a93798d0..d305d5631e 100644 --- a/usr/src/uts/common/inet/mib2.h +++ b/usr/src/uts/common/inet/mib2.h @@ -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 @@ typedef uint32_t DeviceIndex; /* Interface index */ #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 @@ typedef struct mib2_ip { 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 @@ typedef struct mib2_ipv6AddrEntry { } 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 @@ typedef struct mib2_ipv6RouteEntry { } 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 @@ typedef struct ipv6_member { 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 diff --git a/usr/src/uts/common/inet/nd.h b/usr/src/uts/common/inet/nd.h index d990cbbf02..7f851fadaa 100644 --- a/usr/src/uts/common/inet/nd.h +++ b/usr/src/uts/common/inet/nd.h @@ -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" { diff --git a/usr/src/uts/common/inet/optcom.c b/usr/src/uts/common/inet/optcom.c index 8e4ce9358a..355d95a416 100644 --- a/usr/src/uts/common/inet/optcom.c +++ b/usr/src/uts/common/inet/optcom.c @@ -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 @@ opt_length_ok(opdes_t *optd, struct T_opthdr *opt) } 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); +} diff --git a/usr/src/uts/common/inet/optcom.h b/usr/src/uts/common/inet/optcom.h index 84a64c5317..1e93497939 100644 --- a/usr/src/uts/common/inet/optcom.h +++ b/usr/src/uts/common/inet/optcom.h @@ -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_req(queue_t *, mblk_t *, cred_t *, optdb_obj_t *); 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__) */ diff --git a/usr/src/uts/common/inet/rawip_impl.h b/usr/src/uts/common/inet/rawip_impl.h index 5af03c3521..8e61fc9ee7 100644 --- a/usr/src/uts/common/inet/rawip_impl.h +++ b/usr/src/uts/common/inet/rawip_impl.h @@ -98,8 +98,9 @@ typedef struct icmp_s { 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 @@ typedef struct icmp_s { 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 */ diff --git a/usr/src/uts/common/inet/sctp/sctp.c b/usr/src/uts/common/inet/sctp/sctp.c index c840d3e4e6..33820e4cb4 100644 --- a/usr/src/uts/common/inet/sctp/sctp.c +++ b/usr/src/uts/common/inet/sctp/sctp.c @@ -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 @@ extern mblk_t *sctp_pad_mp; /* pad unaligned data chunks */ 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_init(); 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_create_eager(sctp_t *psctp) 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 @@ sctp_create_eager(sctp_t *psctp) 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_clean_death(sctp_t *sctp, int err) (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 @@ sctp_disconnect(sctp_t *sctp) 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 @@ sctp_disconnect(sctp_t *sctp) 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 @@ void 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 @@ sctp_free(conn_t *connp) 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 @@ sctp_icmp_error(sctp_t *sctp, mblk_t *mp) 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 @@ sctp_create(void *sctp_ulpd, sctp_t *parent, int family, int flags, 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_create(void *sctp_ulpd, sctp_t *parent, int family, int flags, 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)); diff --git a/usr/src/uts/common/inet/sctp/sctp_addr.c b/usr/src/uts/common/inet/sctp/sctp_addr.c index f44424a411..089ac791a8 100644 --- a/usr/src/uts/common/inet/sctp/sctp_addr.c +++ b/usr/src/uts/common/inet/sctp/sctp_addr.c @@ -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 @@ sctp_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid, 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_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid, 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 @@ sctp_get_all_ipifs(sctp_t *sctp, int sleep) 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 && diff --git a/usr/src/uts/common/inet/sctp/sctp_asconf.c b/usr/src/uts/common/inet/sctp/sctp_asconf.c index 5afa8b4177..6dfa20b156 100644 --- a/usr/src/uts/common/inet/sctp/sctp_asconf.c +++ b/usr/src/uts/common/inet/sctp/sctp_asconf.c @@ -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 @@ sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid, 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 @@ sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid, /* 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 @@ sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid, } /* 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 @@ sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid, */ 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 @@ sctp_addip_req(sctp_t *sctp, sctp_parm_hdr_t *ph, uint32_t cid, /* 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); } /* diff --git a/usr/src/uts/common/inet/sctp/sctp_asconf.h b/usr/src/uts/common/inet/sctp/sctp_asconf.h index 64327dbd1b..1d9db7e31e 100644 --- a/usr/src/uts/common/inet/sctp/sctp_asconf.h +++ b/usr/src/uts/common/inet/sctp/sctp_asconf.h @@ -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 @@ extern "C" { 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; \ } diff --git a/usr/src/uts/common/inet/sctp/sctp_bind.c b/usr/src/uts/common/inet/sctp/sctp_bind.c index 8ca7d3b4d0..9933bf4996 100644 --- a/usr/src/uts/common/inet/sctp/sctp_bind.c +++ b/usr/src/uts/common/inet/sctp/sctp_bind.c @@ -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 @@ sctp_select_port(sctp_t *sctp, in_port_t *requested_port, int *user_specified) * 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 @@ sctp_select_port(sctp_t *sctp, in_port_t *requested_port, int *user_specified) dprint(1, ("sctp_bind(x): no prive for port %d", *requested_port)); - return (TACCES); + return (EACCES); } } *user_specified = 1; @@ -201,28 +205,21 @@ sctp_bind(sctp_t *sctp, struct sockaddr *sa, socklen_t len) } 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 @@ sctp_bind_del(sctp_t *sctp, const void *addrs, uint32_t addrcnt, } /* - * 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 "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 set and the requested port + * number is available, then set allocated_port to it. If not available, + * return an error. * - * In either case, when succeeding update the sctp_t to record the port number + * 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 * 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 @@ sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, 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 @@ sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, /* 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_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, */ 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 @@ sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, /* * 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 @@ sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, * 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,13 +666,21 @@ sctp_bindi(sctp_t *sctp, in_port_t port, int bind_to_req_port_only, * - 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 @@ retry: goto retry; } } + + if (is_system_labeled() && + (i = tsol_next_port(zone, port, IPPROTO_SCTP, B_TRUE)) != 0) { + port = i; + goto retry; + } + return (port); } diff --git a/usr/src/uts/common/inet/sctp/sctp_common.c b/usr/src/uts/common/inet/sctp/sctp_common.c index 157b0bc1ab..10ac442105 100644 --- a/usr/src/uts/common/inet/sctp/sctp_common.c +++ b/usr/src/uts/common/inet/sctp/sctp_common.c @@ -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_ire2faddr(sctp_t *sctp, sctp_faddr_t *fp) 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 @@ sctp_ire2faddr(sctp_t *sctp, sctp_faddr_t *fp) 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 @@ set_current: } } -/*ARGSUSED*/ void sctp_faddr2ire(sctp_t *sctp, sctp_faddr_t *fp) { @@ -239,7 +228,7 @@ sctp_faddr2ire(sctp_t *sctp, sctp_faddr_t *fp) 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 @@ sctp_make_mp(sctp_t *sctp, sctp_faddr_t *sendto, int trailer) 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 @@ sctp_compare_faddrsets(sctp_faddr_t *a1, sctp_faddr_t *a2) } /* - * 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); - if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL) { - return (-1); + /* find_tpc automatically does the right thing with IPv4 */ + rhtp = find_tpc(addr, IPV6_VERSION, B_FALSE); + if (rhtp == NULL) + return (EACCES); + + 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; - } else { - /* list is empty */ - ASSERT(sctp->sctp_faddrs == NULL); + if (sctp->sctp_faddrs == NULL) { + ASSERT(sctp->sctp_lastfaddr == NULL); + /* only element on list; first and last are same */ + sctp->sctp_faddrs = sctp->sctp_lastfaddr = faddr; + } else if (first) { + ASSERT(sctp->sctp_lastfaddr != NULL); + faddr->next = sctp->sctp_faddrs; sctp->sctp_faddrs = faddr; + } else { + sctp->sctp_lastfaddr->next = faddr; + sctp->sctp_lastfaddr = faddr; } - sctp->sctp_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_first(sctp_t *sctp, in6_addr_t *addr, int sleep) +sctp_add_faddr(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), + dprint(4, ("add_faddr: %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); + return (sctp_add_faddr_entry(sctp, addr, sleep, B_FALSE)); +} - /* 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++; +/* + * 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) +{ + dprint(4, ("add_faddr_first: %x:%x:%x:%x %d\n", SCTP_PRINTADDR(*addr), + sleep)); - return (0); + return (sctp_add_faddr_entry(sctp, addr, sleep, B_TRUE)); } sctp_faddr_t * @@ -914,6 +952,7 @@ sctp_build_hdrs(sctp_t *sctp) 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 @@ sctp_header_init_ipv6(sctp_t *sctp, int sleep) 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 @@ sctp_set_hdraddrs(sctp_t *sctp) /* 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 @@ sctp_set_hdraddrs(sctp_t *sctp) /* 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 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, 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 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, 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 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, 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 @@ sctp_secure_restart_check(mblk_t *pkt, sctp_chunk_hdr_t *ich, uint32_t ports, 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 @@ sctp_congest_reset(sctp_t *sctp) } } -/* - * 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 @@ faddr_destructor(void *buf, void *cdrarg) } 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 @@ sctp_faddr_init() } void -sctp_faddr_fini() +sctp_faddr_fini(void) { kmem_cache_destroy(sctp_kmem_faddr_cache); } diff --git a/usr/src/uts/common/inet/sctp/sctp_conn.c b/usr/src/uts/common/inet/sctp/sctp_conn.c index 690ea4b4a0..66db656acf 100644 --- a/usr/src/uts/common/inet/sctp/sctp_conn.c +++ b/usr/src/uts/common/inet/sctp/sctp_conn.c @@ -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_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, 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 @@ sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, 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 @@ sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt, /* 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 @@ sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len, * 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 @@ sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen) 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 @@ sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen) switch (sctp->sctp_state) { case SCTPS_IDLE: { - int err; struct sockaddr_storage ss; /* @@ -464,10 +477,10 @@ sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen) * 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 @@ sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen) 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 diff --git a/usr/src/uts/common/inet/sctp/sctp_cookie.c b/usr/src/uts/common/inet/sctp/sctp_cookie.c index 6e8e798921..71fff0067a 100644 --- a/usr/src/uts/common/inet/sctp/sctp_cookie.c +++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c @@ -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 @@ sctp_send_initack(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *initmp) 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 @@ sctp_send_initack(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *initmp) 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 @@ sctp_send_initack(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *initmp) 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 @@ sctp_addrlist2sctp(mblk_t *mp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ich, 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 @@ sctp_addrlist2sctp(mblk_t *mp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ich, 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); diff --git a/usr/src/uts/common/inet/sctp/sctp_error.c b/usr/src/uts/common/inet/sctp/sctp_error.c index f54ba76434..f87ef6724a 100644 --- a/usr/src/uts/common/inet/sctp/sctp_error.c +++ b/usr/src/uts/common/inet/sctp/sctp_error.c @@ -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 @@ sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details, 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 @@ sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details, 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 @@ sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details, 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 diff --git a/usr/src/uts/common/inet/sctp/sctp_hash.c b/usr/src/uts/common/inet/sctp/sctp_hash.c index 2fc9996080..daab131ab7 100644 --- a/usr/src/uts/common/inet/sctp/sctp_hash.c +++ b/usr/src/uts/common/inet/sctp/sctp_hash.c @@ -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 @@ done: 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 @@ sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 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 @@ ip_fanout_sctp(mblk_t *mp, ill_t *recv_ill, ipha_t *ipha, 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, diff --git a/usr/src/uts/common/inet/sctp/sctp_heartbeat.c b/usr/src/uts/common/inet/sctp/sctp_heartbeat.c index 542c5e9549..8da1e7d9b8 100644 --- a/usr/src/uts/common/inet/sctp/sctp_heartbeat.c +++ b/usr/src/uts/common/inet/sctp/sctp_heartbeat.c @@ -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 @@ sctp_return_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *hbcp, mblk_t *mp) 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 @@ sctp_process_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *cp) 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 @@ sctp_process_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *cp) 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 @@ sctp_process_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *cp) 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; } diff --git a/usr/src/uts/common/inet/sctp/sctp_impl.h b/usr/src/uts/common/inet/sctp/sctp_impl.h index b6fd5fef2f..42fff07569 100644 --- a/usr/src/uts/common/inet/sctp/sctp_impl.h +++ b/usr/src/uts/common/inet/sctp/sctp_impl.h @@ -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 @@ extern "C" { #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 @@ typedef struct sctpt_s { 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 @@ typedef struct sctp_reass_s { /* 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 @@ typedef struct sctp_s { 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 @@ typedef struct sctp_s { #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 @@ typedef struct sctp_s { /* 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 @@ extern sctp_t *sctp_addrlist2sctp(mblk_t *, sctp_hdr_t *, sctp_chunk_hdr_t *, 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 int sctp_check_abandoned_msg(sctp_t *, mblk_t *); 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 sctp_t *sctp_create_eager(sctp_t *); 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 void sctp_get_faddr_list(sctp_t *, uchar_t *, size_t); 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 mblk_t *sctp_make_sack(sctp_t *, sctp_faddr_t *, mblk_t *); 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 void sctp_rexmit_timer(sctp_t *, sctp_faddr_t *); 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_initack(sctp_t *, sctp_chunk_hdr_t *, mblk_t *); 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_free(mblk_t *); 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); diff --git a/usr/src/uts/common/inet/sctp/sctp_input.c b/usr/src/uts/common/inet/sctp/sctp_input.c index a9a6cf0903..e17b8ff3ec 100644 --- a/usr/src/uts/common/inet/sctp/sctp_input.c +++ b/usr/src/uts/common/inet/sctp/sctp_input.c @@ -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 @@ sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, } /* 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 @@ sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, } /* 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 @@ sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, } /* 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 @@ sctp_input_add_ancillary(sctp_t *sctp, mblk_t **mp, sctp_data_hdr_t *dcp, } /* 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 @@ noancillary: 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 @@ noancillary: 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 @@ noancillary: 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 @@ noancillary: 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 @@ sctp_data_chunk(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *mp, mblk_t **dups, 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 @@ sctp_make_sack(sctp_t *sctp, sctp_faddr_t *sendto, mblk_t *dups) 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 @@ sctp_make_sack(sctp_t *sctp, sctp_faddr_t *sendto, mblk_t *dups) } 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_sack(sctp_t *sctp, mblk_t *dups) 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 @@ sctp_input_data(sctp_t *sctp, mblk_t *mp, mblk_t *ipsec_mp) /* 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 @@ sctp_input_data(sctp_t *sctp, mblk_t *mp, mblk_t *ipsec_mp) 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. diff --git a/usr/src/uts/common/inet/sctp/sctp_opt_data.c b/usr/src/uts/common/inet/sctp/sctp_opt_data.c index 8299f6cd7b..cd263faeca 100644 --- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c +++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c @@ -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. + * 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. + * Returns 0 on success, errno otherwise. */ static int -sctp_pkt_set(uchar_t *invalp, uint_t inlen, uchar_t **optbufp, uint_t *optlenp) +sctp_opt_set_header(sctp_t *sctp, const void *ptr, uint_t len) { - 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); -} + uint8_t *ip_optp; + sctp_hdr_t *new_sctph; -/* - * 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; + if ((len > SCTP_MAX_IP_OPTIONS_LENGTH) || (len & 0x3)) + return (EINVAL); - switch (optval) { - int off; - case IPOPT_SSRR: - case IPOPT_LSRR: + if (len > IP_MAX_OPT_LENGTH - sctp->sctp_v4label_len) + return (EINVAL); - /* - * 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; + ip_optp = (uint8_t *)sctp->sctp_ipha + IP_SIMPLE_HDR_LENGTH; - 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; + if (sctp->sctp_v4label_len > 0) { + int padlen; + uint8_t opt; - 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++; + /* 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); } - 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. - */ -static int -sctp_opt_set_header(sctp_t *sctp, boolean_t checkonly, const void *ptr, - uint_t len) -{ - char buf[SCTP_MAX_HDR_LENGTH]; - uint_t sctph_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; - 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); - } + /* + * Insert the new user-supplied IP options. + */ + if (len > 0) + bcopy(ptr, ip_optp, len); - 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); + 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 @@ sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen) 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 @@ sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen) * 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 @@ sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen) * 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 @@ sctp_get_opt(sctp_t *sctp, int level, int name, void *ptr, socklen_t *optlen) *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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, * 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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 @@ sctp_set_opt(sctp_t *sctp, int level, int name, const void *invalp, 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; } diff --git a/usr/src/uts/common/inet/sctp/sctp_output.c b/usr/src/uts/common/inet/sctp/sctp_output.c index 1321fe2409..8ded7748c9 100644 --- a/usr/src/uts/common/inet/sctp/sctp_output.c +++ b/usr/src/uts/common/inet/sctp/sctp_output.c @@ -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 @@ sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, * 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 @@ sctp_add_proto_hdr(sctp_t *sctp, sctp_faddr_t *fp, mblk_t *mp, int sacklen, 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 @@ sctp_output(sctp_t *sctp) 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 @@ sctp_make_ftsn_chunk(sctp_t *sctp, sctp_faddr_t *fp, sctp_ftsn_set_t *sets, 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 @@ try_bundle: } 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); diff --git a/usr/src/uts/common/inet/sctp/sctp_snmp.c b/usr/src/uts/common/inet/sctp/sctp_snmp.c index 0987c840b1..f078fb4c20 100644 --- a/usr/src/uts/common/inet/sctp/sctp_snmp.c +++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c @@ -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 @@ sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl) 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 @@ sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl) 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 @@ sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl) 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 @@ sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl) 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 @@ done: (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 @@ done: 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 @@ next_sctp: 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); } diff --git a/usr/src/uts/common/inet/sctp/sctp_timer.c b/usr/src/uts/common/inet/sctp/sctp_timer.c index d46c19bdb0..0b2ae2a7fe 100644 --- a/usr/src/uts/common/inet/sctp/sctp_timer.c +++ b/usr/src/uts/common/inet/sctp/sctp_timer.c @@ -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_timer_free(mblk_t *mp) 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_timer_stop(mblk_t *mp) 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 @@ sctp_update_rtt(sctp_t *sctp, sctp_faddr_t *fp, clock_t delta) 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) { diff --git a/usr/src/uts/common/inet/sctp_ip.h b/usr/src/uts/common/inet/sctp_ip.h index 1921de3b93..e5017d2a71 100644 --- a/usr/src/uts/common/inet/sctp_ip.h +++ b/usr/src/uts/common/inet/sctp_ip.h @@ -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_init(void); 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 *); diff --git a/usr/src/uts/common/inet/tcp.h b/usr/src/uts/common/inet/tcp.h index 1e38314815..7ed4f35564 100644 --- a/usr/src/uts/common/inet/tcp.h +++ b/usr/src/uts/common/inet/tcp.h @@ -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 @@ typedef struct tcp_s { 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); diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index 7c24c353d7..002ef63b89 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -54,6 +54,7 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; #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 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; #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 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; * can be sent out. */ - extern major_t TCP6_MAJ; /* @@ -838,7 +842,6 @@ static int tcp_conprim_opt_process(tcp_t *tcp, mblk_t *mp, 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 @@ static int tcp_host_param_report(queue_t *q, mblk_t *mp, caddr_t cp, 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 @@ static void tcp_fill_header(tcp_t *tcp, uchar_t *rptr, clock_t now, 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 @@ static boolean_t tcp_check_policy(tcp_t *, mblk_t *, ipha_t *, ip6_t *, 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 @@ static uint16_t tcp_g_epriv_ports[TCP_NUM_EPRIV_PORTS] = { 2049, 4045 }; 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 @@ static tcpparam_t tcp_mdt_max_pbufs_param = /* * 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_cleanup(tcp_t *tcp) 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 @@ tcp_accept_swap(tcp_t *listener, tcp_t *acceptor, tcp_t *eager) 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) * 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) } } 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) */ 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) 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 @@ tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp) 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 @@ tcp_bind(tcp_t *tcp, mblk_t *mp) 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 @@ tcp_bind(tcp_t *tcp, mblk_t *mp) * 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 @@ tcp_bind(tcp_t *tcp, mblk_t *mp) * 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 @@ tcp_bind(tcp_t *tcp, mblk_t *mp) } } 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 @@ tcp_bind(tcp_t *tcp, mblk_t *mp) } } 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 @@ do_bind: 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, uint16_t lport; tf_t *tbf; tcp_t *ltcp; + conn_t *lconnp; lport = htons(port); @@ -3368,10 +3500,21 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, * 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, * 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, } 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 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, */ 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 @@ tcp_close(queue_t *q, int flags) 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 @@ tcp_free(tcp_t *tcp) 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 @@ tcp_get_conn(void *arg) 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 @@ tcp_conn_request(void *arg, mblk_t *mp, void *arg2) 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 @@ tcp_conn_request(void *arg, mblk_t *mp, void *arg2) 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 @@ tcp_conn_request(void *arg, mblk_t *mp, void *arg2) 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_connect_ipv4(tcp_t *tcp, mblk_t *mp, ipaddr_t *dstaddrp, in_port_t dstport, * 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 @@ tcp_connect_ipv4(tcp_t *tcp, mblk_t *mp, ipaddr_t *dstaddrp, in_port_t dstport, 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_connect_ipv6(tcp_t *tcp, mblk_t *mp, in6_addr_t *dstaddrp, * 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 @@ tcp_connect_ipv6(tcp_t *tcp, mblk_t *mp, in6_addr_t *dstaddrp, 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 @@ tcp_header_init_ipv4(tcp_t *tcp) { tcph_t *tcph; uint32_t sum; + conn_t *connp; /* * This is a simple initialization. If there's @@ -7813,6 +8034,11 @@ tcp_header_init_ipv4(tcp_t *tcp) 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 @@ tcp_header_init_ipv6(tcp_t *tcp) { tcph_t *tcph; uint32_t sum; + conn_t *connp; /* * This is a simple initialization. If there's @@ -7877,6 +8104,12 @@ tcp_header_init_ipv6(tcp_t *tcp) 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 @@ tcp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 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 @@ tcp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) *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 @@ tcp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) * 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 @@ tcp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 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 @@ 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, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 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 @@ tcp_build_hdrs(queue_t *q, tcp_t *tcp) } /* - * 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 @@ static int 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 = (uint8_t *)tcp->tcp_ipha + IP_SIMPLE_HDR_LENGTH; + if (tcp->tcp_label_len > 0) { + int padlen; + uint8_t opt; - ip_optp = (char *)tcp->tcp_ipha + IP_SIMPLE_HDR_LENGTH; + /* 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 @@ tcp_rput_data(void *arg, mblk_t *mp, void *arg2) 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 @@ tcp_rput_add_ancillary(tcp_t *tcp, mblk_t *mp, ip6_pkt_t *ipp) 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 @@ tcp_rput_add_ancillary(tcp_t *tcp, mblk_t *mp, ip6_pkt_t *ipp) 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 @@ tcp_rput_add_ancillary(tcp_t *tcp, mblk_t *mp, ip6_pkt_t *ipp) 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 @@ tcp_rput_add_ancillary(tcp_t *tcp, mblk_t *mp, ip6_pkt_t *ipp) 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 @@ tcp_rput_add_ancillary(tcp_t *tcp, mblk_t *mp, ip6_pkt_t *ipp) 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 @@ tcp_rput_other(tcp_t *tcp, mblk_t *mp) 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 @@ tcp_rput_other(tcp_t *tcp, mblk_t *mp) 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_rput_other(tcp_t *tcp, mblk_t *mp) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) { 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ tcp_unbind(tcp_t *tcp, mblk_t *mp) * 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,8 +16865,15 @@ tcp_update_next_port(in_port_t port, boolean_t random) } 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 @@ retry: /* * 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; + in_port_t nextport; + boolean_t restart = B_FALSE; - if (next_priv_port < tcp_min_anonpriv_port) { +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 @@ tcp_wput_accept(queue_t *q, mblk_t *mp) 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 @@ tcp_wput(queue_t *q, mblk_t *mp) 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 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) 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 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) 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 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) 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 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) */ 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 @@ tcp_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, 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_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, 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 @@ tcp_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, * 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 @@ tcp_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, * 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_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, 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 @@ tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, 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 @@ tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, 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 @@ tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, } /* * 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 @@ tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len) 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 @@ done: } /* - * 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. diff --git a/usr/src/uts/common/inet/tcp/tcp_opt_data.c b/usr/src/uts/common/inet/tcp/tcp_opt_data.c index 2dd6db079e..2f4139405a 100644 --- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c +++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c @@ -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 @@ opdes_t tcp_opt_arr[] = { { 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), diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c index 16966452b1..2c8a401c05 100644 --- a/usr/src/uts/common/inet/udp/udp.c +++ b/usr/src/uts/common/inet/udp/udp.c @@ -39,7 +39,6 @@ const char udp_version[] = "%Z%%M% %I% %E% SMI"; #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 @@ const char udp_version[] = "%Z%%M% %I% %E% SMI"; /* * 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 @@ static udp_fanout_t *udp_bind_fanout; /* * 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 mblk_t *udp_ip_bind_mp(udp_t *udp, t_scalar_t bind_prim, 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_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha); 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 @@ udpparam_t udp_param_arr[] = { /* 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 @@ udp_exit(conn_t *connp) } /* - * 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; + in_port_t nextport; + boolean_t restart = B_FALSE; - if (next_priv_port < udp_min_anonpriv_port) { +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 @@ udp_bind(queue_t *q, mblk_t *mp) 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 @@ udp_bind(queue_t *q, mblk_t *mp) * 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 @@ udp_bind(queue_t *q, mblk_t *mp) } } + 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 @@ udp_bind(queue_t *q, mblk_t *mp) 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 @@ udp_bind(queue_t *q, mblk_t *mp) 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 @@ udp_bind(queue_t *q, mblk_t *mp) * 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 @@ udp_bind(queue_t *q, mblk_t *mp) } 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 @@ udp_bind(queue_t *q, mblk_t *mp) * 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 @@ udp_bind(queue_t *q, mblk_t *mp) } + 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 @@ bind_failed: 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 @@ udp_close(queue_t *q) 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_close_free(conn_t *connp) 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 @@ udp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 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 @@ udp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 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 @@ udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ 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) { + 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 (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; - } + 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); } + 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, /* * 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 @@ udp_opt_set(queue_t *q, uint_t optset_context, int level, 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 @@ udp_build_hdrs(queue_t *q, udp_t *udp) } /* - * 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 @@ udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 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 @@ udp_input(conn_t *connp, mblk_t *mp) 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 @@ udp_input(conn_t *connp, mblk_t *mp) 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 @@ udp_input(conn_t *connp, mblk_t *mp) 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 @@ udp_input(conn_t *connp, mblk_t *mp) } if (udp->udp_ipv6_recvhopopts && (ipp.ipp_fields & IPPF_HOPOPTS)) { - struct T_opthdr *toh; + size_t hlen; - 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; + hlen = copy_hop_opts(&ipp, dstopt); + dstopt += hlen; + udi_size -= hlen; } if (udp->udp_ipv6_recvdstopts && udp->udp_ipv6_recvrthdr && @@ -4803,7 +5094,7 @@ udp_input(conn_t *connp, mblk_t *mp) 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 @@ udp_rput_other(queue_t *q, mblk_t *mp) 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 @@ udp_rput_other(queue_t *q, mblk_t *mp) 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) { 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ udp_snmp_get(queue_t *q, mblk_t *mpctl) 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 @@ udp_unbind(queue_t *q, mblk_t *mp) /* * 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 @@ udp_update_next_port(in_port_t port, boolean_t random) } 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 @@ retry: 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 @@ udp_output_v4(conn_t *connp, mblk_t *mp, ipaddr_t v4dst, uint16_t port, /* * 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 @@ udp_output_v4(conn_t *connp, mblk_t *mp, ipaddr_t v4dst, uint16_t port, } /* 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 @@ udp_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha) 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 @@ udp_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha) 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) * 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 @@ udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 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 @@ udp_wput_data(queue_t *q, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) * 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 @@ udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen, 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 @@ udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen, /* * 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; + 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; - ASSERT(*error == 0); } + 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 @@ udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen, 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 @@ no_options: /* * 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 @@ no_options: 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 @@ udp_wput_iocdata(queue_t *q, mblk_t *mp) 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 @@ udp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp, 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 @@ udp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp, */ *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) { /* diff --git a/usr/src/uts/common/inet/udp/udp_opt_data.c b/usr/src/uts/common/inet/udp/udp_opt_data.c index df3f224eb8..58836f3cb1 100644 --- a/usr/src/uts/common/inet/udp/udp_opt_data.c +++ b/usr/src/uts/common/inet/udp/udp_opt_data.c @@ -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 @@ opdes_t udp_opt_arr[] = { }, { 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, diff --git a/usr/src/uts/common/inet/udp_impl.h b/usr/src/uts/common/inet/udp_impl.h index b943dcdccd..e5bb291a3f 100644 --- a/usr/src/uts/common/inet/udp_impl.h +++ b/usr/src/uts/common/inet/udp_impl.h @@ -48,6 +48,7 @@ extern "C" { #include <inet/common.h> #include <inet/ip.h> +#include <inet/optcom.h> #define UDP_MOD_ID 5607 @@ -122,7 +123,9 @@ typedef struct udp_s { 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 @@ typedef struct udp_s { 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 @@ typedef struct udpahdr_s { 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 boolean_t udp_compute_checksum(void); 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 diff --git a/usr/src/uts/common/io/tl.c b/usr/src/uts/common/io/tl.c index 0648ae2ef1..7302b0f177 100644 --- a/usr/src/uts/common/io/tl.c +++ b/usr/src/uts/common/io/tl.c @@ -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 boolean_t tl_icon_hasprim(tl_endpt_t *, t_scalar_t, t_scalar_t); 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_conn_req_ser(mblk_t *mp, tl_endpt_t *tep) 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 @@ tl_conn_res(mblk_t *mp, tl_endpt_t *tep) 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_unitdata(mblk_t *mp, tl_endpt_t *tep) 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 @@ tl_merror(queue_t *wq, mblk_t *mp, int error) } 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 @@ tl_fill_option(uchar_t *buf, cred_t *cr, pid_t cpid, int flag) 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 @@ tl_fill_option(uchar_t *buf, cred_t *cr, pid_t cpid, int flag) 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); } } diff --git a/usr/src/uts/common/net/route.h b/usr/src/uts/common/net/route.h index 324d630ba3..a9fd9fb691 100644 --- a/usr/src/uts/common/net/route.h +++ b/usr/src/uts/common/net/route.h @@ -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 @@ typedef struct rt_msghdr { #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 diff --git a/usr/src/uts/common/netinet/ip6.h b/usr/src/uts/common/netinet/ip6.h index e9a0d6bf00..cc218df372 100644 --- a/usr/src/uts/common/netinet/ip6.h +++ b/usr/src/uts/common/netinet/ip6.h @@ -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 @@ struct ip6_opt { #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 @@ struct ip6_opt_home_address { /* 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 diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h index d6011d4005..043014ff37 100644 --- a/usr/src/uts/common/nfs/nfs.h +++ b/usr/src/uts/common/nfs/nfs.h @@ -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 int nfsauth_access(struct exportinfo *exi, struct svc_req *req); 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); diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c index e2c9e971bc..e6452fe4f2 100644 --- a/usr/src/uts/common/os/cred.c +++ b/usr/src/uts/common/os/cred.c @@ -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 @@ static int get_c2audit_load(void); #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 @@ cred_init(void) 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 @@ cred_init(void) 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 @@ cralloc(void) 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 @@ crget(void) 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 @@ crhold(cred_t *cr) /* * 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 @@ crcopy(cred_t *cr) 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 @@ crcopy_to(cred_t *oldcr, cred_t *newcr) 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 @@ crdup(cred_t *cr) 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 @@ crdup_to(cred_t *oldcr, cred_t *newcr) 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 @@ crdup_to(cred_t *oldcr, cred_t *newcr) * Return the (held) credentials for the current running process. */ cred_t * -crgetcred() +crgetcred(void) { cred_t *cr; proc_t *p; @@ -500,7 +528,9 @@ crgetauinfo_modifiable(cred_t *cr) 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 @@ crgetprojid(const cred_t *cr) 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 @@ cred2prcred(const cred_t *cr, prcred_t *pcrp) } 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 @@ cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo) 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 @@ cred2ucred(const cred_t *cr, pid_t pid, void *buf) 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 @@ pgetucred(proc_t *p) 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 @@ crsetzone(cred_t *cr, zone_t *zptr) 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); +} diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index a9753c3df6..a3cd19e423 100644 --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -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 @@ gexec( 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 @@ execsetid(struct vnode *vp, struct vattr *vattrp, uid_t *uidp, uid_t *gidp) !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. diff --git a/usr/src/uts/common/os/labelsys.c b/usr/src/uts/common/os/labelsys.c new file mode 100644 index 0000000000..a59b21cd90 --- /dev/null +++ b/usr/src/uts/common/os/labelsys.c @@ -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, ¤t->rhc_host)) + break; + prevp = ¤t->rhc_next; + } + + if (current != NULL) { + DTRACE_PROBE(tx__tndb__l2__tnrhdelete_existingrhentry); + *prevp = current->rhc_next; + mutex_enter(¤t->rhc_lock); + current->rhc_next = NULL; + current->rhc_invalid = 1; + mutex_exit(¤t->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 */ +} diff --git a/usr/src/uts/common/os/main.c b/usr/src/uts/common/os/main.c index e6c502c118..2d5f6d5fdf 100644 --- a/usr/src/uts/common/os/main.c +++ b/usr/src/uts/common/os/main.c @@ -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> diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c index 2e027b7ba5..dcad0a7535 100644 --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -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 @@ secpolicy_net_privaddr(const cred_t *cr, in_port_t port) } /* + * 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 @@ secpolicy_sti(const cred_t *cr) 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) { diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs index 9377dc63c5..adfd62853b 100644 --- a/usr/src/uts/common/os/priv_defs +++ b/usr/src/uts/common/os/priv_defs @@ -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 @@ privilege PRIV_FILE_DAC_WRITE 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 @@ privilege PRIV_FILE_SETID 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 @@ privilege PRIV_IPC_OWNER 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 @@ privilege PRIV_SYS_TIME 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. diff --git a/usr/src/uts/common/os/sysent.c b/usr/src/uts/common/os/sysent.c index fff7f4cc74..e1caaaa778 100644 --- a/usr/src/uts/common/os/sysent.c +++ b/usr/src/uts/common/os/sysent.c @@ -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 hrtsys(); int ioctl(); int issetugid(); int kill(); +int labelsys(); int link(); off32_t lseek32(); off_t lseek64(); @@ -664,7 +664,7 @@ struct sysent sysent[NSYSCALL] = /* 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 @@ struct sysent sysent[NSYSCALL] = 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 @@ struct sysent sysent32[NSYSCALL] = /* 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), diff --git a/usr/src/uts/common/os/tlabel.c b/usr/src/uts/common/os/tlabel.c new file mode 100644 index 0000000000..20ea2d5156 --- /dev/null +++ b/usr/src/uts/common/os/tlabel.c @@ -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); +} diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index c4bb5af10c..a34da6e75a 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -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 zone_key_t zsd_keyval = 0; 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 kcondvar_t mount_cv; 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 @@ static int zone_shutdown(zoneid_t zoneid); * 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 @@ zone_zsd_init(void) } /* + * 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 @@ zone_init(void) * 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 @@ zone_free(zone_t *zone) 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 @@ zone_free(zone_t *zone) 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 @@ zone_find_all_by_id(zoneid_t zoneid) } 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 @@ zone_find_by_id(zoneid_t zoneid) } /* + * 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 @@ zone_create_error(int er_error, int er_ext, int *er_out) { 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 @@ parse_zfs(zone_t *zone, caddr_t ubuf, size_t buflen) /* * 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 @@ static zoneid_t 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 @@ zone_create(const char *zone_name, const char *zone_root, 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 @@ zone_create(const char *zone_name, const char *zone_root, } /* + * 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 @@ zone_create(const char *zone_name, const char *zone_root, 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 @@ zone_create(const char *zone_name, const char *zone_root, (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 @@ zone_create(const char *zone_name, const char *zone_root, */ 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 @@ zone_empty(zone_t *zone) } /* + * 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 @@ zone_destroy(zoneid_t zoneid) (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_getattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize) 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 @@ zone_getattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize) 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 @@ zone_getattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize) 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 @@ zone_getattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize) if (err != 0 && err != ENAMETOOLONG) error = EFAULT; } - if (global) + if (global || (is_system_labeled() && !curzone)) kmem_free(zonepath, size); break; @@ -3388,6 +3616,17 @@ zone_getattr(zoneid_t zoneid, int attr, void *buf, size_t bufsize) 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 @@ out: * 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 @@ zone_list(zoneid_t *zoneidlist, uint_t *numzones) 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 @@ zone_list(zoneid_t *zoneidlist, uint_t *numzones) /* * 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 @@ zone_lookup(const char *zone_name) 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 @@ zone(int cmd, void *arg1, void *arg2, void *arg3, void *arg4) 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 @@ zone(int cmd, void *arg1, void *arg2, void *arg3, void *arg4) 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 @@ zone_dataset_visible(const char *dataset, int *write) 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); +} diff --git a/usr/src/uts/common/rpc/clnt_clts.c b/usr/src/uts/common/rpc/clnt_clts.c index affd816ae7..e1a40d7df4 100644 --- a/usr/src/uts/common/rpc/clnt_clts.c +++ b/usr/src/uts/common/rpc/clnt_clts.c @@ -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 @@ endpnt_get(struct knetconfig *config, int useresvport) 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 @@ top: /* * 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 @@ top: * 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 @@ top: 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 @@ top: * 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; diff --git a/usr/src/uts/common/rpc/clnt_cots.c b/usr/src/uts/common/rpc/clnt_cots.c index e5a7e5b3d7..bf47961d9f 100644 --- a/usr/src/uts/common/rpc/clnt_cots.c +++ b/usr/src/uts/common/rpc/clnt_cots.c @@ -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 @@ use_new_conn: 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; diff --git a/usr/src/uts/common/rpc/svc.c b/usr/src/uts/common/rpc/svc.c index 7b64094313..af7843de1b 100644 --- a/usr/src/uts/common/rpc/svc.c +++ b/usr/src/uts/common/rpc/svc.c @@ -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( "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 @@ svc_getreq( 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 @@ svc_getreq( } } + if (r.rq_label != NULL) + kmem_free(r.rq_label, sizeof (bslabel_t)); + /* * Free authentication parameters' storage */ @@ -1442,7 +1469,6 @@ svc_clone_free(SVCXPRT *clone_xprt) /* Fre credentials from crget() */ if (clone_xprt->xp_cred) crfree(clone_xprt->xp_cred); - kmem_free(clone_xprt, sizeof (SVCXPRT)); } @@ -1480,6 +1506,7 @@ svc_clone_link(SVCMASTERXPRT *xprt, SVCXPRT *clone_xprt) /* 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 @@ svc_queuereq(queue_t *q, mblk_t *mp) 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 diff --git a/usr/src/uts/common/rpc/svc.h b/usr/src/uts/common/rpc/svc.h index dc78550aae..10636ebd70 100644 --- a/usr/src/uts/common/rpc/svc.h +++ b/usr/src/uts/common/rpc/svc.h @@ -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 svc_req { 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 SVCXPRT *svc_door_create(); extern int svc_dg_enablecache(); #endif /* __STDC__ */ +extern boolean_t is_multilevel(rpcprog_t); + #ifdef PORTMAP /* For backward compatibility */ #include <rpc/svc_soc.h> diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 516ecc0a5a..94069abd27 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -841,6 +841,13 @@ RSMHDRS= \ 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 @@ CHECKHDRS= \ $(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 @@ CHECKHDRS= \ $(ROOTHOTPLUGHDRS) \ $(ROOTHOTPLUGPCIHDRS) \ $(ROOTRSMHDRS) \ + $(ROOTTSOLHDRS) \ $($(MACH)_ROOTHDRS) @@ -1029,6 +1038,7 @@ install_h: \ $(ROOTHOTPLUGHDRS) \ $(ROOTHOTPLUGPCIHDRS) \ $(ROOTRSMHDRS) \ + $(ROOTTSOLHDRS) \ $($(MACH)_ROOTHDRS) all_h: $(GENHDRS) diff --git a/usr/src/uts/common/sys/Makefile.syshdrs b/usr/src/uts/common/sys/Makefile.syshdrs index d9c363b48b..22283c9f83 100644 --- a/usr/src/uts/common/sys/Makefile.syshdrs +++ b/usr/src/uts/common/sys/Makefile.syshdrs @@ -111,6 +111,9 @@ usb/clients/printer/%.check: usb/clients/printer/%.h 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 @@ ROOTDIRS= \ $(ROOTDIR)/usb/clients/ugen \ $(ROOTDIR)/1394 \ $(ROOTDIR)/rsm \ + $(ROOTDIR)/tsol \ $($(MACH)_ROOTDIRS) @@ -234,6 +238,7 @@ ROOTI2OHDRS= $(I2OHDRS:%=$(ROOTDIR)/i2o/%) 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)/1394/%: 1394/% $(ROOTDIR)/rsm/%: rsm/% $(INS.file) +$(ROOTDIR)/tsol/%: tsol/% + $(INS.file) + $(ROOTDIRS): $(INS.dir) diff --git a/usr/src/uts/common/sys/cred.h b/usr/src/uts/common/sys/cred.h index 971e39443c..c1400b83d7 100644 --- a/usr/src/uts/common/sys/cred.h +++ b/usr/src/uts/common/sys/cred.h @@ -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 supgroupmember(gid_t, const cred_t *); 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 gid_t crgetsgid(const cred_t *); 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 @@ extern int crsetgroups(cred_t *, int, gid_t *); */ 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 cred_t *crnetadjust(cred_t *); */ 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 diff --git a/usr/src/uts/common/sys/cred_impl.h b/usr/src/uts/common/sys/cred_impl.h index 811b8dcd3f..ef31b60922 100644 --- a/usr/src/uts/common/sys/cred_impl.h +++ b/usr/src/uts/common/sys/cred_impl.h @@ -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 @@ extern "C" { #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 @@ struct cred { 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 */ diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h index beabb63818..6492501176 100644 --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -102,10 +102,13 @@ int secpolicy_kmdb(const cred_t *); 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 *); diff --git a/usr/src/uts/common/sys/priv.h b/usr/src/uts/common/sys/priv.h index c80debcd65..ffab3a7648 100644 --- a/usr/src/uts/common/sys/priv.h +++ b/usr/src/uts/common/sys/priv.h @@ -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 @@ typedef struct priv_impl_info { #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_set_PA(cred_t *); 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 diff --git a/usr/src/uts/common/sys/socket.h b/usr/src/uts/common/sys/socket.h index 18acac99b0..a43edfd1ce 100644 --- a/usr/src/uts/common/sys/socket.h +++ b/usr/src/uts/common/sys/socket.h @@ -142,6 +142,8 @@ typedef void *_RESTRICT_KYWD Psocklen_t; #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) */ diff --git a/usr/src/uts/common/sys/strsun.h b/usr/src/uts/common/sys/strsun.h index 6b56681d2d..987d25dd10 100644 --- a/usr/src/uts/common/sys/strsun.h +++ b/usr/src/uts/common/sys/strsun.h @@ -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 @@ extern "C" { #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 *); diff --git a/usr/src/uts/common/sys/syscall.h b/usr/src/uts/common/sys/syscall.h index 5a907fd7a9..43dee30f0b 100644 --- a/usr/src/uts/common/sys/syscall.h +++ b/usr/src/uts/common/sys/syscall.h @@ -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 @@ extern "C" { * 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 diff --git a/usr/src/uts/common/sys/tsol/label.h b/usr/src/uts/common/sys/tsol/label.h new file mode 100644 index 0000000000..0eec1b497d --- /dev/null +++ b/usr/src/uts/common/sys/tsol/label.h @@ -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 */ diff --git a/usr/src/uts/common/sys/tsol/label_macro.h b/usr/src/uts/common/sys/tsol/label_macro.h new file mode 100644 index 0000000000..43cf328e7d --- /dev/null +++ b/usr/src/uts/common/sys/tsol/label_macro.h @@ -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 */ diff --git a/usr/src/uts/common/sys/tsol/priv.h b/usr/src/uts/common/sys/tsol/priv.h new file mode 100644 index 0000000000..24ec85c9bd --- /dev/null +++ b/usr/src/uts/common/sys/tsol/priv.h @@ -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 */ diff --git a/usr/src/uts/common/sys/tsol/tndb.h b/usr/src/uts/common/sys/tsol/tndb.h new file mode 100644 index 0000000000..0b211c8968 --- /dev/null +++ b/usr/src/uts/common/sys/tsol/tndb.h @@ -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 */ diff --git a/usr/src/uts/common/sys/tsol/tnet.h b/usr/src/uts/common/sys/tsol/tnet.h new file mode 100644 index 0000000000..0b5e5185b2 --- /dev/null +++ b/usr/src/uts/common/sys/tsol/tnet.h @@ -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 */ diff --git a/usr/src/uts/common/sys/tsol/tsyscall.h b/usr/src/uts/common/sys/tsol/tsyscall.h new file mode 100644 index 0000000000..3f9d1e12aa --- /dev/null +++ b/usr/src/uts/common/sys/tsol/tsyscall.h @@ -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 */ diff --git a/usr/src/uts/common/sys/ucred.h b/usr/src/uts/common/sys/ucred.h index a3f229dc44..c7247baafa 100644 --- a/usr/src/uts/common/sys/ucred.h +++ b/usr/src/uts/common/sys/ucred.h @@ -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 @@ struct ucred_s { 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 @@ struct ucred_s { #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 @@ extern uint32_t ucredsize; #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 @@ extern int get_audit_ucrsize(void); 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); diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h index 441ea8cb3e..ef07aa2877 100644 --- a/usr/src/uts/common/sys/zone.h +++ b/usr/src/uts/common/sys/zone.h @@ -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 @@ extern "C" { #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 @@ extern "C" { #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 @@ typedef struct { 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 @@ typedef struct { 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 @@ typedef struct zone_cmd_rval { */ #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 @@ typedef struct zone { * 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_cred_rele(zone_t *); 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 @@ struct zsd_entry { #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. */ diff --git a/usr/src/uts/common/syscall/ppriv.c b/usr/src/uts/common/syscall/ppriv.c index 817c4fc83b..2013d70caa 100644 --- a/usr/src/uts/common/syscall/ppriv.c +++ b/usr/src/uts/common/syscall/ppriv.c @@ -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 @@ getprivimplinfo(void *buf, size_t bufsize) } /* - * 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 @@ setpflags(uint_t flag, uint_t val) 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 @@ setpflags(uint_t flag, uint_t val) /* 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 @@ setpflags(uint_t flag, uint_t val) 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 @@ setpflags(uint_t flag, uint_t val) /* * 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 @@ getpflags(uint_t flag) 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 @@ privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize) 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)); } diff --git a/usr/src/uts/common/syscall/sendfile.c b/usr/src/uts/common/syscall/sendfile.c index 8978d27fec..a7ad930011 100644 --- a/usr/src/uts/common/syscall/sendfile.c +++ b/usr/src/uts/common/syscall/sendfile.c @@ -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> diff --git a/usr/src/uts/common/syscall/ucredsys.c b/usr/src/uts/common/syscall/ucredsys.c index 16e4ce82b8..38d13884c7 100644 --- a/usr/src/uts/common/syscall/ucredsys.c +++ b/usr/src/uts/common/syscall/ucredsys.c @@ -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 @@ getpeerucred(int fd, void *buf) 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 @@ ucred_get(pid_t pid, void *ubuf) return (set_errno(err)); } - uc = cred2ucred(pcr, pid, NULL); + uc = cred2ucred(pcr, pid, NULL, CRED()); crfree(pcr); diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c index 0f41488b9d..b58cad94f8 100644 --- a/usr/src/uts/i86pc/os/startup.c +++ b/usr/src/uts/i86pc/os/startup.c @@ -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 @@ startup_modules(void) if (modload("fs", "devfs") == -1) halt("Can't load devfs"); + (void) modloadonly("sys", "lbl_edition"); + dispinit(); /* @@ -2411,7 +2400,7 @@ uint64_t mtrrdef, pat_attr_reg; int enable_relaxed_mtrr = 0; void -setup_mtrr() +setup_mtrr(void) { int i, ecx; int vcnt; @@ -2463,7 +2452,7 @@ setup_mtrr() * 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 @@ mtrr_sync() * 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 @@ mtrr_resync() } void -get_system_configuration() +get_system_configuration(void) { char prop[32]; u_longlong_t nodes_ll, cpus_pernode_ll, lvalue; diff --git a/usr/src/uts/req.flg b/usr/src/uts/req.flg index ba8db470d9..36f48f01be 100644 --- a/usr/src/uts/req.flg +++ b/usr/src/uts/req.flg @@ -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/fs 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 diff --git a/usr/src/uts/sun4/os/startup.c b/usr/src/uts/sun4/os/startup.c index 91ab3df934..2051840ae2 100644 --- a/usr/src/uts/sun4/os/startup.c +++ b/usr/src/uts/sun4/os/startup.c @@ -1638,6 +1638,8 @@ startup_modules(void) if (modloadonly("misc", "swapgeneric") == -1) halt("Can't load swapgeneric"); + (void) modloadonly("sys", "lbl_edition"); + dispinit(); /* |