--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/cups/patches/18-audit-tx.patch Mon Jan 07 21:53:27 2013 -0800
@@ -0,0 +1,1260 @@
+--- configure.in Thu Jan 3 02:44:26 2013
++++ configure.in Wed Jan 2 21:45:05 2013
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -125,7 +125,7 @@
+ BANNERTOPS = @[email protected]
+ CFLAGS = @[email protected] @[email protected]
+ COMMONLIBS = @[email protected]
+-CUPSDLIBS = @[email protected] @[email protected]
++CUPSDLIBS = @[email protected] @[email protected] @[email protected]
+ CXXFLAGS = @[email protected] @[email protected]
+ CXXLIBS = @[email protected]
+ DBUS_NOTIFIER = @[email protected]
+--- scheduler/client.h Wed Jan 2 23:21:36 2013
++++ scheduler/client.h Wed Jan 2 21:44:36 2013
[email protected]@ -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...
[email protected]@ -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
[email protected]@ -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...
+ */
[email protected]@ -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
[email protected]@ -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.
[email protected]@ -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);
+ }
[email protected]@ -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);
[email protected]@ -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);
+ }
[email protected]@ -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;
[email protected]@ -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;
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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);
+
[email protected]@ -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.
[email protected]@ -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;
+ }
[email protected]@ -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
[email protected]@ -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...
+ */
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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));
[email protected]@ -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);
+
+ /*
[email protected]@ -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));
[email protected]@ -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...
+ */