components/cups/patches/18-audit-tx.patch
author Mike Sullivan <Mike.Sullivan@Oracle.COM>
Mon, 11 Mar 2013 10:38:09 -0700
branchs11-update
changeset 2520 ceec631e74d1
parent 2490 ee4391c71c07
permissions -rw-r--r--
Close of build 10.

--- configure.in	Thu Jan  3 02:44:26 2013
+++ configure.in	Wed Jan  2 21:45:05 2013
@@ -42,6 +42,7 @@
 sinclude(config-scripts/cups-pdf.m4)
 sinclude(config-scripts/cups-scripting.m4)
 sinclude(config-scripts/cups-labeling.m4)
+sinclude(config-scripts/cups-auditing.m4)
 
 INSTALL_LANGUAGES=""
 UNINSTALL_LANGUAGES=""
--- config-scripts/cups-auditing.m4	Wed Jan  2 23:23:52 2013
+++ config-scripts/cups-auditing.m4	Wed Jan  2 21:45:18 2013
@@ -0,0 +1,35 @@
+dnl
+dnl    Auditing support for the Common UNIX Printing System (CUPS).
+dnl
+dnl    Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+dnl
+dnl   This program is free software; you can redistribute it and/or modify
+dnl   it under the terms of the GNU General Public License as published by
+dnl   the Free Software Foundation; version 2.
+dnl
+dnl   This program is distributed in the hope that it will be useful, but
+dnl   WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl   General Public License for more details.
+dnl
+dnl   You should have received a copy of the GNU General Public License
+dnl   along with this program; if not, write to the Free Software Foundation,
+dnl   Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA
+dnl
+
+AC_ARG_ENABLE(auditing, [ --enable-auditing enable support for auditing, default=auto])
+
+if test x"$enable_auditing" != xno; then
+    case "$uname" in
+        SunOS)
+		AC_CHECK_LIB(bsm, adt_start_session,
+		    [AUDITING_LIBS="-lbsm" AC_SUBST(AUDITING_LIBS)
+		    AC_CHECK_HEADER(bsm/adt.h)
+		    AC_CHECK_HEADER(bsm/adt_event.h)
+		    AC_DEFINE(HAVE_ADT)])
+            ;;
+        *)
+            # All others
+            ;;
+    esac
+fi
--- config.h.in	Wed Jan  2 23:21:36 2013
+++ config.h.in	Wed Jan  2 21:44:45 2013
@@ -672,6 +672,11 @@
 #undef HAVE_TSOL
 
 /*
+ * Do we have Auditing support ?
+ */
+#undef HAVE_ADT
+
+/*
  * Do we have SELinux support?
  */
 #undef HAVE_SELINUX
--- Makedefs.in	Wed Jan  2 23:21:36 2013
+++ Makedefs.in	Wed Jan  2 21:46:40 2013
@@ -125,7 +125,7 @@
 BANNERTOPS	=	@BANNERTOPS@
 CFLAGS		=	@CPPFLAGS@ @CFLAGS@
 COMMONLIBS	=	@LIBS@
-CUPSDLIBS	=	@CUPSDLIBS@ @LABELING_LIBS@
+CUPSDLIBS	=	@CUPSDLIBS@ @LABELING_LIBS@ @AUDITING_LIBS@
 CXXFLAGS	=	@CPPFLAGS@ @CXXFLAGS@
 CXXLIBS		=	@CXXLIBS@
 DBUS_NOTIFIER	=	@DBUS_NOTIFIER@
--- scheduler/client.h	Wed Jan  2 23:21:36 2013
+++ scheduler/client.h	Wed Jan  2 21:44:36 2013
@@ -17,6 +17,9 @@
 #  include <Security/Authorization.h>
 #endif /* HAVE_AUTHORIZATION_H */
 
+#ifdef HAVE_ADT
+#include <bsm/adt.h>
+#endif /* HAVE_ADT */
 
 /*
  * HTTP client structure...
@@ -64,8 +67,13 @@
 #ifdef HAVE_AUTHORIZATION_H
   AuthorizationRef	authref;	/* Authorization ref */
 #endif /* HAVE_AUTHORIZATION_H */
-  char                  *slabel;		/* security context for security
+#ifdef HAVE_TSOL
+  char                  *slabel;	/* security context for security
 					   labeled environments */
+#endif /* HAVE_TSOL */
+#ifdef HAVE_ADT
+  adt_session_data_t	*ah		/* audit handle for print requests */
+#endif /* HAVE_ADT */
 };
 
 #define HTTP(con) &((con)->http)
--- scheduler/job.h	Wed Jan  2 23:21:36 2013
+++ scheduler/job.h	Wed Jan  2 21:46:16 2013
@@ -13,6 +13,10 @@
  *   file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
+#ifdef HAVE_ADT
+#include <bsm/adt.h>
+#endif /* HAVE_ADT */
+
 /*
  * Constants...
  */
@@ -83,8 +87,13 @@
   krb5_ccache		ccache;		/* Kerberos credential cache */
   char			*ccname;	/* KRB5CCNAME environment variable */
 #endif /* HAVE_GSSAPI */
-  char                  *slabel;		/* security context for security
+#ifdef HAVE_TSOL
+  char                  *slabel;	/* security context for security
 					   labeled environments */
+#endif /* HAVE_TSOL */
+#ifdef HAVE_ADT
+  adt_session_data_t	*ah;		/* audit handle for print requests */
+#endif /* HAVE_ADT */
 };
 
 typedef struct cupsd_joblog_s		/**** Job log message ****/
--- scheduler/ipp.c	Wed Jan  2 23:21:36 2013
+++ scheduler/ipp.c	Wed Jan  2 23:25:46 2013
@@ -1425,12 +1425,20 @@
 		*media_margin;		/* media-*-margin attribute */
   ipp_t		*unsup_col;		/* media-col in unsupported response */
 
-
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
                   con, con->http.fd, printer, printer->name,
 		  filetype, filetype ? filetype->super : "none",
 		  filetype ? filetype->type : "none");
 
+#if defined(HAVE_TSOL)
+  /* Start audit session to audit CUPS print requests */
+  if (is_system_labeled() != 0) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: Start CUPS audit session"
+		    " for connection");
+    cups_audit_start_session(con);
+  }
+#endif /* HAVE_TSOL */
+
   /*
    * Validate that the label associated with the connection is acceptable for
    * printing on the printer.
@@ -1437,6 +1445,11 @@
    */
   if (cupsdInPrinterLabelRange(con->slabel, printer) == 0)
   {
+#if defined(HAVE_TSOL)
+    /* Audit the print request */
+    if (is_system_labeled() != 0)
+      cups_audit_print_request_denial(con, NULL, printer, -1, EACCES);
+#endif /* HAVE_TSOL */
     send_ipp_status(con, IPP_NOT_AUTHORIZED, _("label violation."));
     return (NULL);
   }
@@ -1450,6 +1463,12 @@
       strcasecmp(con->http.hostname, "localhost") &&
       strcasecmp(con->http.hostname, ServerName))
   {
+#if defined(HAVE_TSOL)
+    /* Audit the print request */
+    if (is_system_labeled() != 0)
+      cups_audit_print_request_denial(con, NULL, printer, -1, EPERM);
+#endif /* HAVE_TSOL */
+
     send_ipp_status(con, IPP_NOT_AUTHORIZED,
                     _("The printer or class is not shared!"));
     return (NULL);
@@ -1463,6 +1482,11 @@
 
   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
   {
+#if defined(HAVE_TSOL)
+    /* Audit the print request */
+    if (is_system_labeled() != 0)
+      cups_audit_print_request_denial(con, NULL, printer, -1, EPERM);
+#endif /* HAVE_TSOL */
     send_http_error(con, status, printer);
     return (NULL);
   }
@@ -1714,6 +1738,21 @@
 		 NULL, label_to_page_top_bottom_string(job->slabel));
   }
 
+#if defined(HAVE_TSOL)
+  /*
+   * Initialize audit handle for job.
+   * Audit handle for job is same as that for connection.
+   * Connection handle is not available in job.c where job requests
+   * are processed so the same is copied to job handle so that
+   * job requests can be audited.
+   * Here just the handle pointer is being copied. It will stay valid
+   * throughout the processing of a print request.
+   */
+  if (is_system_labeled() != 0)
+    job->ah = con->ah;
+
+#endif /* HAVE_TSOL */
+
   job->dtype   = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
                                   CUPS_PRINTER_REMOTE);
   job->attrs   = con->request;
@@ -1851,6 +1890,7 @@
   */
 
   ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
   job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
                              "job-state", IPP_JOB_STOPPED);
   job->state_value = (ipp_jstate_t)job->state->values[0].integer;
@@ -4081,6 +4121,11 @@
     if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
                                    NULL)) != HTTP_OK)
     {
+#if defined(HAVE_TSOL)
+      /* Audit the print request */
+      if (is_system_labeled() != 0)
+        cups_audit_print_request_denial(con, NULL, printer, -1, EPERM);
+#endif /* HAVE_TSOL */
       send_http_error(con, status, printer);
       return;
     }
--- scheduler/job.c	Wed Jan  2 23:21:36 2013
+++ scheduler/job.c	Wed Jan  2 21:46:11 2013
@@ -75,6 +75,9 @@
 #include <cups/backend.h>
 #include <cups/dir.h>
 
+#if defined(HAVE_TSOL)
+#include <bsm/adt_event.h>
+#endif /* HAVE_TSOL */
 
 /*
  * Design Notes for Job Management
@@ -2712,6 +2715,9 @@
   const char		*message;	/* Message for job state */
   char			buffer[1024];	/* Buffer for formatted messages */
 
+#if defined(HAVE_TSOL)
+  ipp_attribute_t	*attr;		/* Current attributes */
+#endif /* HAVE_TSOL */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
 
@@ -2986,6 +2992,13 @@
 		  "error_log file for details.";
     }
   }
+#if defined(HAVE_TSOL)
+  /* Audit the print request. */
+  if (is_system_labeled() != 0) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "finalize_job(cups_audit_print_request)");
+    cups_audit_print_request(job, job_state);
+  }
+#endif /* HAVE_TSOL */
 
  /*
   * Update the printer and job state.
@@ -4037,6 +4050,12 @@
                     "start_job(): job label outside of printer label range");
     cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
                      "job label is outside of printer label range");
+#if defined(HAVE_TSOL)
+    if (is_system_labeled() != 0)
+	cups_audit_print_request_denial(NULL, job, printer,
+				    job->state_value, EACCES);
+#endif /*HAVE_TSOL */
+
     cupsdCheckJobs();
     return;
   }
@@ -4586,7 +4605,6 @@
    /*
     * Handle the end of job stuff...
     */
-
     finalize_job(job, 1);
 
    /*
--- scheduler/cups-lpd.c	Wed Sep  3 05:57:17 2008
+++ scheduler/cups-lpd.c	Wed Jan  2 21:45:33 2013
@@ -348,8 +348,11 @@
   ipp_attribute_t *attr;		/* IPP attribute */
   char		uri[HTTP_MAX_URI];	/* Printer URI */
   int		id;			/* Job ID */
+#if defined(HAVE_TSOL)
+  char		*hostname;
+  const char    uid[11], gid[11];	/* user id and group id */
+#endif /* HAVE_TSOL */
 
-
  /*
   * Setup the Create-Job request...
   */
@@ -373,6 +376,29 @@
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", 
                  NULL, docname);
 
+#if defined(HAVE_TSOL)
+  if (is_system_labeled() != 0) {
+    /* Add job-originating-host-name to the request */
+    if ((hostname = cupsGetOption("job-originating-host-name", num_options,
+	options)) != NULL)
+      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+		   "job-originating-host-name", NULL, hostname);
+
+    /* Add userID and groupID of the user who submitted the request */
+
+    /*
+     * When uid and gid are added to the attributes using ippAddInteger,
+     * ippFindAttribute from the scheduler is not able to read the attribute,
+     * so using ippAddString to add uid and gid.
+     */
+    snprintf(uid, sizeof(uid), "%d", getuid());
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "userID", NULL, uid);
+
+    snprintf(gid, sizeof(gid), "%d", getgid());
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "groupID", NULL, gid);
+  }
+#endif /* HAVE_TSOL */
+
   cupsEncodeOptions(request, num_options, options);
 
  /*
--- scheduler/audit.c	Wed Jan  2 23:26:12 2013
+++ scheduler/audit.c	Wed Jan  2 21:44:22 2013
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA
+ */
+#include <syslog.h>
+#include "cupsd.h"
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+#include <auth_attr.h>
+
+#define	PRINT_UNLABELED_AUTH	"solaris.print.unlabeled"
+#define	PRINT_NOBANNER_AUTH	"solaris.print.nobanner"
+
+/*
+ * Maximum length of string to hold requested job id:
+ * <printer-name>-<job-id>
+ * IPP_MAX_NAME+1+10+1
+ */
+#define	REQ_MAX_NAME		IPP_MAX_NAME+1+10+1
+
+uid_t	uid = ADT_NO_ATTRIB;
+gid_t	gid = ADT_NO_ATTRIB;
+
+void cups_audit_start_session(cupsd_client_t *con);
+void cups_audit_print_request_denial(cupsd_client_t *con, cupsd_job_t *job,
+     cupsd_printer_t *printer, ipp_jstate_t job_state, int fail_reason);
+void cups_audit_print_request(cupsd_job_t *job, ipp_jstate_t job_state);
+
+/*
+ * Set up an audit session for auditing the current print request.
+ */
+void
+cups_audit_start_session(cupsd_client_t *con)
+{
+
+	if (adt_start_session(&con->ah, NULL, 0) != 0) {
+		cupsdLogMessage(CUPSD_LOG_EMERG, "cups_audit_start_session(): "
+		    "adt_start_session(): %d", errno);
+		con->ah = NULL;
+		return;
+	}
+
+	if (strcasecmp(con->http.hostname, "localhost") == 0) {
+		/* Local Request */
+		ucred_t *cred = NULL;
+
+		if (getpeerucred(con->http.fd, &cred) == -1) {
+			cupsdLogMessage(CUPSD_LOG_EMERG,
+			    "cups_audit_start_session(): "
+			    "getpeerucred(): %d", errno);
+			(void) adt_end_session(con->ah);
+			con->ah = NULL;
+			return;
+		}
+
+		if (adt_set_from_ucred(con->ah, cred, ADT_NEW) != 0) {
+			cupsdLogMessage(CUPSD_LOG_EMERG,
+			    "cups_audit_start_session(): "
+			    "adt_set_from_ucred(): %d", errno);
+			(void) adt_end_session(con->ah);
+			con->ah = NULL;
+			return;
+		}
+	} else {
+		/* Remote Request */
+		ipp_attribute_t	*userID = NULL, *grpID = NULL;
+		adt_termid_t	*termid = NULL;
+
+		if ((userID = ippFindAttribute(con->request, "userID",
+		    IPP_TAG_NAME)) != NULL) {
+			cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cups_audit_start_session():"
+			    "userID = %s", userID->values[0].string.text);
+			uid = atoi(userID->values[0].string.text);
+		} else {
+			cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cups_audit_start_session():"
+			    "userID = NULL");
+		}
+
+		if ((grpID = ippFindAttribute(con->request, "groupID",
+		    IPP_TAG_NAME)) != NULL) {
+			cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cups_audit_start_session():"
+			    "grpID = %s", grpID->values[0].string.text);
+			gid = atoi(grpID->values[0].string.text);
+		} else {
+			cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cups_audit_start_session():"
+			    "grpID = NULL");
+		}
+
+		if (adt_load_termid(con->http.fd, &termid) != 0) {
+			cupsdLogMessage(CUPSD_LOG_ERROR,
+			    "cups_audit_start_session(): "
+			    "adt_load_termid(): %d", errno);
+		}
+		if (adt_set_user(con->ah, uid, gid, uid, gid, termid,
+		    ADT_NEW) != 0) {
+			cupsdLogMessage(CUPSD_LOG_EMERG,
+			    "cups_audit_start_session(): "
+			    "adt_set_user(): %d", errno);
+			(void) adt_end_session(con->ah);
+			con->ah = NULL;
+			free(termid);
+			return;
+		}
+		free(termid);
+	}
+}
+
+/*
+ * Routine for filling in the audit event details for each of the
+ * three types of TX-related printing audit records:
+ *    AUE_print_request - audit each file in print request
+ *    AUE_print_request_unlabeled - audit use of the solaris.print.nolabels auth
+ *    AUE_print_request_nobanner - audit use of the solaris.print.nobanner auth
+ * One AUE_print_request audit record is written for each text file in the
+ * print request. The '-o nolabels' and '-o nobanner' options apply to the
+ * entire print request so one AUE_print_request_unlabeled audit record and one
+ * AUE_print_request_nobanner audit record is written, respectively, for each
+ * file in the print request when these options are supplied.
+ * 
+ * event_ID		= type of TX-related printing audit record
+ * event		= audit event structure
+ * printer		= printer name
+ * slabel		= Sensitivity Label
+ * job_ID		= request_ID; <printe-name>-<job-id>
+ * job_ID_remote	= remote request_ID; <printe-name>-<remote-job_id>
+ *			job id for the same request differ on client and server
+ * filelist		= file to be printed;
+ *			 In case 'filelist' is 'stdin', temporary filename
+ *			 created in /var/spool/cups/ is read 
+ * ai			= struct addrinfo; 
+ * status 		= audit request status;
+ *			 ADT_FAILURE, ADT_SUCCESS
+ * return_val		= return value of audit request;
+ *			 If user is not authorized then ADT_FAIL_VALUE_AUTH
+ *			 If print job is successfully completed then ADT_SUCCESS
+ *			 If job is cancelled then
+ *			 ADT_FAIL_VALUE_PRINT_JOB_CANCELLED
+ *			MAC failures it is EACESS
+ *			DAC failures it is EPERM
+ * i = which of the job files is this 000-999 for the CUPS max of 
+ *	1000 jobs.  See util.c
+ * job_id 		= print request job id; this is used to get the location
+ *			 of the temporary file in spool directory which is of the format:
+ *			 /var/spool/cups/d00550-001
+ *			where 550 is the job-id.
+ * remote		= true: remote request
+ *			 false: local request
+ */
+static void
+cups_audit_print_request_data(au_event_t event_ID,
+    adt_event_data_t *event, char *printer, char *slabel,
+    char *job_ID, char *job_ID_remote, char *filelist,
+    struct addrinfo *ai, int status, int return_val, int i,
+    int job_id, boolean_t remote)
+{
+	char		tmpfile[IPP_MAX_NAME];
+	char		tfile[IPP_MAX_NAME];
+	char		r_job_ID[IPP_MAX_NAME];
+	char		*file, *f_job_ID = NULL;
+	struct stat	attributes;
+	m_label_t	*file_label = NULL;
+
+	/*
+	 * If 'filelist' is 'stdin', read the temporary filename
+	 * created for the file contents in /var/spool/cups/
+	 * This will be useful to audit the files printed
+	 * via standard input.
+	 * Scheduler can't discern the difference between a
+	 * file printed via stdin and one printed normally so
+	 * the file attributes and label are always included
+	 * even though they refer to the temporary file created
+	 * in the case of stdin.
+	 * The label is going to be the same regardless of wheather
+	 * it is of the tmp file that was used for stdin or the real file.
+	 */
+	if (remote) {
+	    	/*
+		 * temporary filename is of the format:
+		 * /var/spool/cups/d00550-001
+		 * where 550 is the job-id.
+		 */
+		snprintf(tmpfile, sizeof (tmpfile), "%s/d%05d-%03d",
+		    RequestRoot, job_id, i + 1);
+		/*
+		 * In case of remote request,
+		 * Job_ID string is like:
+		 * 'Local JOB_ID: <printer>-id |
+		 * Remote JOB_ID: <printer>-<remote-id>'
+		 */
+		if (job_ID_remote != NULL) {
+			snprintf(r_job_ID, sizeof (r_job_ID),
+			    "Local JOB_ID: %s |"
+			    " Remote JOB_ID: %s-%s",
+			    job_ID, printer, job_ID_remote);
+			f_job_ID = r_job_ID;
+		} else {
+			f_job_ID = job_ID;
+		}
+
+	} else {
+		f_job_ID = job_ID;
+		if (job_id != -1) {
+			if ((strncmp(filelist, "(stdin)", 7)) == 0) {
+				snprintf(tmpfile, sizeof (tmpfile),
+				    "%s/d%05d-%03d", RequestRoot,
+				    job_id, i + 1);
+			} else {
+				strlcpy(tmpfile, filelist, sizeof (tmpfile));
+			}
+		} else {
+			strlcpy(tmpfile, filelist, sizeof (tmpfile));
+		}
+	}
+
+	file = tmpfile;
+
+	if (stat(file, &attributes) == -1) {
+		cupsdLogMessage(CUPSD_LOG_ERROR,
+		    "cups_audit_print_request_data():"
+		    "stat(): %d", errno);
+	}
+
+	/*
+	 * In case of remote request, filelist contains client document-name.
+	 * Append the same to filename before writing to the audit record.
+	 */
+	if (remote && (filelist != NULL)) {
+		strlcpy(tfile, "Local file: ", sizeof (tmpfile));
+		strcat(tfile, tmpfile);
+		strcat(tfile, " | Remote file: ");
+		strcat(tfile, filelist);
+		file = tfile;
+	}
+
+	/* extract label from slabel */
+	if (str_to_label(slabel, &file_label, MAC_LABEL,
+	    L_NO_CORRECTION, NULL) == 0) {
+		cupsdLogMessage(CUPSD_LOG_DEBUG2,
+		    "cups_audit_print_request_data():"
+		    "file_label extracted");
+	} else {
+		cupsdLogMessage(CUPSD_LOG_ERROR,
+		    "cups_audit_print_request_data():"
+		    "file_label not extracted");
+	}
+
+	/* Populate audit event structure */
+	switch (event_ID) {
+	case ADT_print_request_unlabeled:
+		if (remote) {
+			if (ai->ai_family == AF_INET) {
+				event->adt_print_request_unlabeled.
+				    remote_host_ip_type = ADT_IPv4;
+				    
+				(void) memcpy(event->
+				    adt_print_request_unlabeled.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in *)ai->
+				    ai_addr)->sin_addr,
+				    sizeof (struct in_addr));
+			} else if (ai->ai_family == AF_INET6) {
+				event->adt_print_request_unlabeled.
+				    remote_host_ip_type = ADT_IPv6;
+				    
+				(void) memcpy(event->
+				    adt_print_request_unlabeled.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in6 *)ai->
+				    ai_addr)->sin6_addr,
+				    sizeof (struct in6_addr));
+			}
+		}
+		event->adt_print_request_unlabeled.request_ID = f_job_ID;
+		event->adt_print_request_unlabeled.printer = printer;
+		event->adt_print_request_unlabeled.file = file;
+		event->adt_print_request_unlabeled.file_attrs = &attributes;
+		event->adt_print_request_unlabeled.file_label = file_label;
+		event->adt_print_request_unlabeled.override_auth =
+		    PRINT_UNLABELED_AUTH;
+		break;
+	case ADT_print_request_nobanner:
+		if (remote) {
+			if (ai->ai_family == AF_INET) {
+				event->adt_print_request_nobanner.
+				    remote_host_ip_type = ADT_IPv4;
+				    
+				(void) memcpy(event->
+				    adt_print_request_nobanner.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in *)ai->
+				    ai_addr)->sin_addr,
+				    sizeof (struct in_addr));
+			} else if (ai->ai_family == AF_INET6) {
+				event->adt_print_request_nobanner.
+				    remote_host_ip_type = ADT_IPv6;
+				    
+				(void) memcpy(event->
+				    adt_print_request_nobanner.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in6 *)ai->
+				    ai_addr)->sin6_addr,
+				    sizeof (struct in6_addr));
+			}
+		}
+		event->adt_print_request_nobanner.request_ID = f_job_ID;
+		event->adt_print_request_nobanner.printer = printer;
+		event->adt_print_request_nobanner.file = file;
+		event->adt_print_request_nobanner.file_attrs = &attributes;
+		event->adt_print_request_nobanner.file_label = file_label;
+		event->adt_print_request_nobanner.override_auth =
+		    PRINT_NOBANNER_AUTH;
+		break;
+	case ADT_print_request:
+		if (remote) {
+			if (ai->ai_family == AF_INET) {
+				event->adt_print_request.
+				    remote_host_ip_type = ADT_IPv4;
+				    
+				(void) memcpy(event->
+				    adt_print_request.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in *)ai->
+				    ai_addr)->sin_addr,
+				    sizeof (struct in_addr));
+			} else if (ai->ai_family == AF_INET6) {
+				event->adt_print_request.
+				    remote_host_ip_type = ADT_IPv6;
+				    
+				(void) memcpy(event->
+				    adt_print_request.
+				    remote_host_ipaddress,
+				    &((struct sockaddr_in6 *)ai->
+				    ai_addr)->sin6_addr,
+				    sizeof (struct in6_addr));
+			}
+		}
+		event->adt_print_request.request_ID = f_job_ID;
+		event->adt_print_request.printer = printer;
+		event->adt_print_request.file = file;
+		event->adt_print_request.file_attrs = &attributes;
+		event->adt_print_request.file_label = file_label;
+		break;
+	}
+
+	if (adt_put_event(event, status, return_val) != 0) {
+		cupsdLogMessage(CUPSD_LOG_EMERG,
+		    "cups_audit_print_request_data():"
+		    "adt_put_event(): %d", errno);
+	}
+}
+
+/*
+ * To populate the audit events, cups_audit_print_request() is called.
+ * cups_audit_print_request() calls cups_audit_print_request_common()
+ * which in turn calls cups_audit_print_request_sub() which finally
+ * calls cups_audit_print_request_data().
+ *
+ * event_ID		= type of TX-related printing audit record
+ *			 ADT_print_request_unlabeled
+ *			 ADT_print_request_nobanner
+ *			 ADT_print_request 
+ * ah 			= Audit session handle
+ * printer              = printer name
+ * job_ID		= request_ID; <printe-name>-<job-id> 
+ * job_id		= job->id; Job identification number.
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.	
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.	
+ * job_ID_remote	= remote request_ID; <printe-name>-<remote-job_id>
+ *			 local job_id and remote job_id are different
+ * job_state		= ipp_jstate_t enum:
+ *	IPP_JOB_PENDING = 3,	Job is waiting to be printed
+ *	IPP_JOB_HELD,		Job is held for printing
+ * 	IPP_JOB_PROCESSING,	Job is currently printing
+ * 	IPP_JOB_STOPPED,	Job has been stopped
+ * 	IPP_JOB_CANCELED,	Job has been canceled
+ * 	IPP_JOB_ABORTED,	Job has aborted due to error
+ * 	IPP_JOB_COMPLETED	Job has completed successfully
+ *			 current job state 
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.
+ * job_state_value 	= ipp_jstate_t; cached job state
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.
+ * hostname		= name of connected host
+ * document_list	= list of files to be printed
+ * job_name		= job title; usually the first filename in filelist
+ * slabel		= Sensitivity Label 
+ * fail_reason 		= failure reason; EPERM, EACESS
+ * authorized		= true: user has required autorization to print
+ *			 false: user is not authorized to print 
+ * num_files		= 0 for initial MAC/DAC
+ *			 1 - 999 for number of files printed in a job.       
+ * wants_nobanner	= true: user does not want to print banner and trailer page
+ *			 false: user wants to print banner and trailer page 
+ */
+static void
+cups_audit_print_request_sub(au_event_t event_ID, adt_session_data_t *ah,
+    char *printer, char *job_ID, int job_id, char *job_ID_remote,
+    ipp_jstate_t job_state, ipp_jstate_t job_state_value, char *hostname,
+    char *document_list, char *job_name, char *slabel, int fail_reason,
+    int authorized, int num_files, boolean_t wants_nobanner)
+{
+	adt_event_data_t	*event;
+	char			*dlist, *filelist;
+	int			status, return_val;
+	struct addrinfo		*ai = NULL;
+	boolean_t		remote = B_FALSE;
+
+	if ((event = adt_alloc_event(ah, event_ID)) == NULL) {
+		cupsdLogMessage(CUPSD_LOG_EMERG,
+		    "cups_audit_print_request_sub():"
+		    "adt_alloc_event(): %d", errno);
+		return;
+	}
+
+	if ((job_id == -1) && (job_state == -1) && (job_state_value == -1)) {
+		status = ADT_FAILURE;
+		return_val = fail_reason;
+	} else {
+		if (authorized != 1) {
+			status = ADT_FAILURE;
+			return_val = ADT_FAIL_VALUE_AUTH;
+		} else {
+			if (job_state == IPP_JOB_COMPLETED) {
+				status = ADT_SUCCESS;
+				return_val = ADT_SUCCESS;
+			} else {
+				status = ADT_FAILURE;
+				if ((fail_reason == 0) &&
+				    (job_state_value == IPP_JOB_CANCELED)) {
+					return_val =
+					    ADT_FAIL_VALUE_PRINT_JOB_CANCELLED;
+				} else if (fail_reason == 0) {
+					return_val =
+					    ADT_FAIL_VALUE_PRINT_JOB_FAILED;
+				} else {
+					return_val = fail_reason;
+				}
+			}
+		}
+	}
+
+	if (hostname != NULL) {
+		int err;
+
+		cupsdLogMessage(CUPSD_LOG_DEBUG,
+		    "cups_audit_print_request_sub():"
+		    "host = %s", hostname);
+		if ((err = getaddrinfo(hostname,
+		    NULL, NULL, &ai)) != 0) {
+			cupsdLogMessage(CUPSD_LOG_ERROR,
+			    "cups_audit_print_request_sub():"
+			    "getaddrinfo(%s) failed[%s]",
+			    hostname, gai_strerror(err));
+
+		}
+		if (strcasecmp(hostname, "localhost") != 0) {
+			remote = B_TRUE;
+		}
+	} else {
+		cupsdLogMessage(CUPSD_LOG_DEBUG,
+		    "cups_audit_print_request_sub():"
+		    "host is NULL");
+	}
+
+	if (document_list == NULL) {
+		dlist = job_name;
+	} else {
+		dlist = document_list;
+		cupsdLogMessage(CUPSD_LOG_DEBUG2,
+		    "cups_audit_print_request_sub():"
+		    "document-names is %s ", dlist);
+	}
+
+	/*
+	 * document-names=f1,f2,f3...
+	 * extract the files from it.
+	 */
+	if (dlist != NULL) {
+		filelist = strtok(dlist, ",");
+	}
+
+	if (remote) {
+		/* Remote Request */
+		int i = 1;
+		int max_files = (num_files - 1);
+
+		/*
+		 * remote root always sends banner and trailer files
+		 * to the server. Whereas in case of non-root if
+		 * nobanner is set it sends only the job file to
+		 * the server.
+		 */
+		if ((uid != 0) && (gid != 0) && wants_nobanner) {
+			i = 0;
+			max_files = num_files;
+		}
+
+		for (; i < max_files; i++) {
+			cups_audit_print_request_data(event_ID,
+			    event, printer, slabel, job_ID, job_ID_remote,
+			    filelist, ai, status, return_val,
+			    i, job_id, remote);
+
+			if (filelist != NULL) {
+				filelist = strtok(NULL, ",");
+			}
+		}
+	} else {
+		/* Local Request */
+		while (filelist != NULL) {
+			cups_audit_print_request_data(event_ID,
+			    event, printer, slabel, job_ID, job_ID_remote,
+			    filelist, ai, status, return_val,
+			    0, job_id, remote);
+			filelist = strtok(NULL, ",");
+		}
+	}
+
+	if (ai != NULL) {
+		freeaddrinfo(ai);
+	}
+
+	adt_free_event(event);
+}
+
+/*
+ * To populate the audit events, cups_audit_print_request() is called.
+ * cups_audit_print_request() calls cups_audit_print_request_common()
+ * which in turns calls cups_audit_print_request_sub() which finally
+ * calls cups_audit_print_request_data().
+ *
+ * ah 			= Audit session handle
+ * request_ID		= <printer-name>-<job_id>;
+ *			 <printer-name>-none in case of denial request when
+ *			 a request is denied before job gets created.
+ * job_id		= job->id; Job identification number.
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.	
+ * job_state		= ipp_jstate_t enum:
+ *	IPP_JOB_PENDING = 3,	Job is waiting to be printed
+ *	IPP_JOB_HELD,		Job is held for printing
+ * 	IPP_JOB_PROCESSING,	Job is currently printing
+ * 	IPP_JOB_STOPPED,	Job has been stopped
+ * 	IPP_JOB_CANCELED,	Job has been canceled
+ * 	IPP_JOB_ABORTED,	Job has aborted due to error
+ * 	IPP_JOB_COMPLETED	Job has completed successfully
+ *			 current job state 
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.
+ * job_state_value 	= ipp_jstate_t; cached job state
+ *			 -1 in case of denial request when
+ *			 a request is denied before job gets created.
+ * ipp 			= ipp_t; Request information
+ * printer 		= cupsd_printer_t
+ * slabel 		= Sensitivity Label
+ * username 		= Username from Authorization
+ * hname 		= name of connected host
+ * fail_reason 		= failure reason; EPERM, EACESS
+ * num_files		= 0 for initial MAC/DAC
+ *			 1 - 999 for number of files printed in a job.       
+ * denial_request	= false if cups_audit_print_request()
+ *			 true if cups_audit_print_request_denial()
+ */
+static void
+cups_audit_print_request_common(adt_session_data_t *ah,
+    char *request_ID, int job_id, ipp_jstate_t job_state,
+    ipp_jstate_t job_state_value, ipp_t *ipp, cupsd_printer_t *printer,
+    char *slabel, char *username, char *hname, int fail_reason,
+    int num_files, boolean_t denial_request)
+{
+	int		authorized = 0;
+	boolean_t	wants_nobanner = B_FALSE;
+	boolean_t	wants_nolabels = B_FALSE;
+	ipp_attribute_t	*attr = NULL;
+	char		*document_list = NULL, *job_name = NULL;
+	char		*hostname = NULL, *job_id_remote = NULL;
+
+	/*
+	 * Read 'document-names', 'job-name',
+	 * 'job-id-remote' and 'job-originating-host-name'
+	 * from request.
+	 */
+	if ((attr = ippFindAttribute(ipp, "document-names",
+	    IPP_TAG_NAME)) != NULL) {
+		document_list = attr->values[0].string.text;
+	}
+
+	if ((attr = ippFindAttribute(ipp, "job-name", IPP_TAG_NAME)) != NULL) {
+		job_name = attr->values[0].string.text;
+	}
+
+	/* If input hostname is NULL, then read hostname from job */
+	if (hname == NULL) {
+		if ((attr = ippFindAttribute(ipp, "job-originating-host-name",
+		    IPP_TAG_NAME)) != NULL) {
+			hostname = attr->values[0].string.text;
+		}
+	} else {
+		hostname = hname;
+	}
+
+	if ((attr = ippFindAttribute(ipp, "job-id-remote",
+	    IPP_TAG_NAME)) != NULL) {
+		job_id_remote = attr->values[0].string.text;
+	}
+
+	/*
+	 * '-o job-sheets=none,none' means
+	 * user does not want to print banner and trailer page.
+	 * In trusted system, '-o job-sheets=none' and '-o job-sheets=none,none'
+	 * means same.
+	 */
+	if ((attr = ippFindAttribute(ipp, "job-sheets",
+	    IPP_TAG_ZERO)) != NULL) {
+		if (strcmp(attr->values[0].string.text, "none") == 0) {
+			wants_nobanner = B_TRUE;
+		}
+	}
+
+	if (wants_nobanner) {
+		authorized = chkauthattr(PRINT_NOBANNER_AUTH, username);
+
+		/*
+		 * In case of normal print request
+		 * fail_reason is based on authorized.
+		 */
+		if (!denial_request) {
+			if (authorized) {
+				fail_reason = 0;
+			} else {
+				fail_reason = ADT_FAIL_VALUE_AUTH;
+			}
+		}
+
+		cups_audit_print_request_sub(
+		    ADT_print_request_nobanner, ah, printer->name,
+		    request_ID, job_id, job_id_remote, job_state,
+		    job_state_value, hostname, document_list,
+		    job_name, slabel, fail_reason,
+		    authorized, num_files, wants_nobanner);
+	}
+
+	/* chk for 'nolabels' in request */
+	if (ippFindAttribute(ipp, "labels", IPP_TAG_ZERO) != NULL) {
+		wants_nolabels = B_TRUE;
+
+		authorized = chkauthattr(PRINT_UNLABELED_AUTH, username);
+
+		/*
+		 * In case of normal print request
+		 * fail_reason is based on authorized.
+		 */
+		if (!denial_request) {
+			if (authorized) {
+				fail_reason = 0;
+			} else {
+				fail_reason = ADT_FAIL_VALUE_AUTH;
+			}
+		}
+
+		cups_audit_print_request_sub(
+		    ADT_print_request_unlabeled, ah, printer->name,
+		    request_ID, job_id, job_id_remote, job_state,
+		    job_state_value, hostname, document_list,
+		    job_name, slabel, fail_reason,
+		    authorized, num_files, wants_nobanner);
+	}
+
+	if (!wants_nolabels && !wants_nobanner) {
+		/*
+		 * In case of normal print request
+		 * fail_reason is based on authorized.
+		 */
+		if (!denial_request) {
+			fail_reason = 0;
+		}
+
+		cups_audit_print_request_sub(
+		    ADT_print_request, ah, printer->name,
+		    request_ID, job_id, job_id_remote, job_state,
+		    job_state_value, hostname, document_list,
+		    job_name, slabel, fail_reason,
+		    1, num_files, wants_nobanner);
+	}
+
+	(void) adt_end_session(ah);
+}
+
+/*
+ * Routine for auditing print requests which have been validated.
+ * This means user has all of the required authorizations, the
+ * ability to print to the designated printer and the printer is
+ * within the user's label range.
+ *
+ * cupsd_job_[s]t int id			Job ID
+ *		ipp_jstate_t state_value	Cached job-state
+ *		char *slabel			Sensitivity Label
+ *		adt_session_data *ah		Audit session handle
+ *		char *username			Printing user
+ *		int num_files			Number of files in job
+ *		ipp_t *attrs			Job attributes
+ *			place to get attributes of job such as
+ *			document-names, job-name, job-originating-host-name,
+ *			job-id-remote, job-sheets, labels
+ *		cupsd_printer_t *printer	Printer this job is assigned to
+ *			char *name	Printer name
+ */
+void
+cups_audit_print_request(cupsd_job_t *job, ipp_jstate_t job_state)
+{
+	char	request_ID[REQ_MAX_NAME];
+
+	snprintf(request_ID, sizeof (request_ID), "%s-%d",
+	    job->printer->name, job->id);
+
+	cups_audit_print_request_common(job->ah, request_ID,
+	    job->id, job_state, job->state_value, job->attrs,
+	    job->printer, job->slabel, job->username, NULL, 0,
+	    job->num_files, B_FALSE);
+}
+
+/*
+ * Routine for auditing print request which have been denied due
+ * to lack of authorization or the printer access list is configured
+ * to deny access to the user.
+ * 'fail_reason' will be either EPERM or EACCES based on DAC or MAC
+ * failure resp.
+ *
+ * cupsd_client_[s]t
+ *	adt_session_data_t	*ah	Audit session handle
+ *	ipp_t	*request	IPP request information
+ *		appears equivalent to job->attrs above.
+ *	char	*slabel		Sesnitivity Label
+ *	char	*username	Username from Authorization
+ *	http_t	http		HTTP client connection
+ *	char    *hostname	name of connected host
+ *
+ */
+void
+cups_audit_print_request_denial(cupsd_client_t *con, cupsd_job_t *job,
+    cupsd_printer_t *printer, ipp_jstate_t job_state, int fail_reason)
+{
+	char request_ID[REQ_MAX_NAME];
+
+	/*
+	 * If connection is not NULL, audit based on connection and
+	 * not job.
+	 */
+	if (con != NULL) {
+		sprintf(request_ID, "%s-none", printer->name);
+		cups_audit_print_request_common(con->ah, request_ID,
+		    -1, -1, -1, con->request, printer, con->slabel,
+		    con->username, con->http.hostname, fail_reason, 0, B_TRUE);
+	} else {
+		sprintf(request_ID, "%s-%d", job->printer->name, job->id);
+		cups_audit_print_request_common(job->ah, request_ID,
+		    job->id, job_state, job->state_value, job->attrs,
+		    printer, job->slabel, job->username, NULL, fail_reason,
+		    job->num_files, B_TRUE);
+	}
+}
--- scheduler/Makefile	Wed Jan  2 23:21:35 2013
+++ scheduler/Makefile	Wed Jan  2 21:46:49 2013
@@ -16,6 +16,7 @@
 include ../Makedefs
 
 CUPSDOBJS =	\
+		audit.o \
 		auth.o \
 		banners.o \
 		cert.o \
--- backend/ipp.c	Thu Jan 14 14:40:19 2010
+++ backend/ipp.c	Wed Jan  2 21:46:02 2013
@@ -893,6 +893,15 @@
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
         	 NULL, uri);
 
+#if defined(HAVE_TSOL)
+    if (is_system_labeled() != 0) {
+      /* Keep a track of the remote job-id */
+      if (argv[1][0])
+	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+		     "job-id-remote", NULL, argv[1]);
+    }
+#endif /* HAVE_TSOL */
+
     fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
 
     if (argv[2][0])
--- cups/util.c	Thu Jan  3 00:07:27 2013
+++ cups/util.c	Thu Jan  3 02:00:02 2013
@@ -220,8 +220,11 @@
 		*response;		/* Create-Job response */
   ipp_attribute_t *attr;		/* job-id attribute */
   int		job_id = 0;		/* job-id value */
+#if defined(HAVE_TSOL)
+  const char	*filelist;		/* list of input files */
+  const char	uid[11], gid[11];	/* user id and group id */
+#endif /* HAVE_TSOL */
 
-
   DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", "
                 "num_options=%d, options=%p)",
                 http, name, title, num_options, options));
@@ -257,6 +260,28 @@
   if (title)
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
                  title);
+
+#if defined(HAVE_TSOL)
+  if (is_system_labeled() != 0) {
+    if ((filelist = cupsGetOption("filelist", num_options, options)) != NULL)
+      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-names",
+                   NULL, filelist);
+
+     /* Add userID and groupID of the user who submitted the request */
+
+     /*
+      * When uid and gid are added to the attributes using ippAddInteger,
+      * ippFindAttribute from the scheduler is not able to read the attribute,
+      * so using ippAddString to add uid and gid.
+      */
+    snprintf(uid, sizeof(uid), "%d", getuid());
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "userID", NULL, uid);
+
+    snprintf(gid, sizeof(gid), "%d", getgid());
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "groupID", NULL, gid);
+  }
+#endif /* HAVE_TSOL */
+
   cupsEncodeOptions(request, num_options, options);
 
  /*
@@ -1462,8 +1487,12 @@
   _cups_globals_t *cg = _cupsGlobals();	/* Global data */
   ipp_status_t	cancel_status;		/* Status code to preserve */
   char		*cancel_message;	/* Error message to preserve */
+#if defined(HAVE_TSOL)
+  int		listlen = 0;
+  char		*filelist;		/* file list */
+  char		resolved_path[PATH_MAX];
+#endif /* HAVE_TSOL */
 
-
   DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, "
                 "files=%p, title=\"%s\", num_options=%d, options=%p)",
                 http, name, num_files, files, title, num_options, options));
@@ -1479,6 +1508,56 @@
     return (0);
   }
 
+#if defined(HAVE_TSOL)
+  if (is_system_labeled() != 0) {
+    /*
+     * Read the list of files and add to options.
+     * In options it will be stored like 'filelist=f1,f2,f3'
+     */
+
+    /*
+     * Maximum number of files to be printed should not be
+     * more than 1000.
+     */
+    if (num_files > 1000)
+        num_files = 1000;
+
+    for(i=0; i<num_files; i++) {
+      if (realpath(files[i], resolved_path) != NULL) {
+        listlen = listlen + strlen(resolved_path);
+      } else
+        listlen = listlen + strlen(files[i]);
+    }
+
+    /*
+     * Add num_files to listlen to make room for ','
+     * and NULL terminated string.
+     */
+    listlen = listlen + num_files;
+    filelist = malloc(listlen);
+
+    if (filelist != NULL) {
+      if (realpath(files[0], resolved_path) != NULL)
+          strlcpy(filelist, resolved_path, listlen);
+      else
+          strlcpy(filelist, files[0], listlen);
+
+      for (i=1; i<num_files; i++)
+      {
+          strlcat(filelist, ",", listlen);
+          if (realpath(files[i], resolved_path) != NULL)
+            strlcat(filelist, resolved_path, listlen);
+          else
+            strlcat(filelist, files[i], listlen);
+      }
+
+      num_options = cupsAddOption("filelist", filelist, num_options, &options);
+
+      free(filelist);
+    }
+  }
+#endif /* HAVE_TSOL */
+
  /*
   * Create the print job...
   */