components/cups/patches/18-audit-tx.patch
author Sonam Gupta <sonam.x.gupta@oracle.com>
Sun, 17 Feb 2013 21:51:48 -0800
branchs11u1-sru
changeset 2495 eb04a6ca141d
permissions -rw-r--r--
15698471 cups should audit printing information in TX environments 14850597 TX printing is reported to print jobs even when request authorization fail. 16182423 Update error code for all the failed use of authorization records in CUPS 16182458 Print 3 files requesting nolabel and nobanner should produce 6 audit records 16201093 For remote print requests, the path token in AR from GZ needs modification

--- 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...
   */