1 diff -up cups-2.2b2/config.h.in.lspp cups-2.2b2/config.h.in
2 --- cups-2.2b2/config.h.in.lspp 2016-06-27 17:39:48.075973879 +0200
3 +++ cups-2.2b2/config.h.in 2016-06-27 17:47:31.376356684 +0200
4 @@ -737,4 +737,11 @@ static __inline int _cups_abs(int i) { r
5 # endif /* __GNUC__ || __STDC_VERSION__ */
6 #endif /* !HAVE_ABS && !abs */
9 + * Are we trying to meet LSPP requirements?
15 #endif /* !_CUPS_CONFIG_H_ */
16 diff -up cups-2.2b2/config-scripts/cups-lspp.m4.lspp cups-2.2b2/config-scripts/cups-lspp.m4
17 --- cups-2.2b2/config-scripts/cups-lspp.m4.lspp 2016-06-27 17:39:48.076973871 +0200
18 +++ cups-2.2b2/config-scripts/cups-lspp.m4 2016-06-27 17:39:48.076973871 +0200
21 +dnl LSPP code for the Common UNIX Printing System (CUPS).
23 +dnl Copyright 2005-2006 by Hewlett-Packard Development Company, L.P.
25 +dnl This program is free software; you can redistribute it and/or modify
26 +dnl it under the terms of the GNU General Public License as published by
27 +dnl the Free Software Foundation; version 2.
29 +dnl This program is distributed in the hope that it will be useful, but
30 +dnl WITHOUT ANY WARRANTY; without even the implied warranty of
31 +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 +dnl General Public License for more details.
34 +dnl You should have received a copy of the GNU General Public License
35 +dnl along with this program; if not, write to the Free Software Foundation,
36 +dnl Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA
39 +dnl Are we trying to meet LSPP requirements
40 +AC_ARG_ENABLE(lspp, [ --enable-lspp turn on auditing and label support, default=no])
42 +if test x"$enable_lspp" != xno; then
45 + AC_CHECK_LIB(audit,audit_log_user_message, [LIBAUDIT="-laudit" AC_SUBST(LIBAUDIT)])
46 + AC_CHECK_HEADER(libaudit.h)
47 + AC_CHECK_LIB(selinux,getpeercon, [LIBSELINUX="-lselinux" AC_SUBST(LIBSELINUX)])
48 + AC_CHECK_HEADER(selinux/selinux.h)
49 + AC_DEFINE(WITH_LSPP)
56 diff -up cups-2.2b2/configure.ac.lspp cups-2.2b2/configure.ac
57 --- cups-2.2b2/configure.ac.lspp 2016-06-24 17:43:35.000000000 +0200
58 +++ cups-2.2b2/configure.ac 2016-06-27 17:39:48.076973871 +0200
59 @@ -38,6 +38,8 @@ sinclude(config-scripts/cups-startup.m4)
60 sinclude(config-scripts/cups-defaults.m4)
61 sinclude(config-scripts/cups-scripting.m4)
63 +sinclude(config-scripts/cups-lspp.m4)
66 UNINSTALL_LANGUAGES=""
68 diff -up cups-2.2b2/filter/common.c.lspp cups-2.2b2/filter/common.c
69 --- cups-2.2b2/filter/common.c.lspp 2016-06-24 17:43:35.000000000 +0200
70 +++ cups-2.2b2/filter/common.c 2016-06-27 17:39:48.076973871 +0200
72 * Include necessary headers...
79 +#endif /* WITH_LSPP */
84 @@ -299,6 +305,18 @@ WriteLabelProlog(const char *label, /* I
86 const char *classification; /* CLASSIFICATION environment variable */
87 const char *ptr; /* Temporary string pointer */
89 + int i, /* counter */
91 + lines, /* number of lines needed */
92 + line_len, /* index into tmp_label */
93 + label_len, /* length of the label in characters */
94 + label_index, /* index into the label */
95 + longest, /* length of the longest line */
96 + longest_line, /* index to the longest line */
97 + max_width; /* maximum width in characters */
98 + char **wrapped_label; /* label with line breaks */
99 +#endif /* WITH_LSPP */
103 @@ -321,6 +339,124 @@ WriteLabelProlog(const char *label, /* I
108 + if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
111 + * Based on the 12pt fixed width font below determine the max_width
113 + max_width = width / 8;
116 + classification += 5; // Skip the "LSPP:"
117 + label_len = strlen(classification);
119 + if (label_len > max_width)
121 + lines = 1 + (int)(label_len / max_width);
122 + line_len = (int)(label_len / lines);
123 + wrapped_label = malloc(sizeof(*wrapped_label) * lines);
124 + label_index = i = n = 0;
125 + while (classification[label_index])
127 + if ((label_index + line_len) > label_len)
129 + switch (classification[label_index + line_len + i])
135 + wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
136 + label_index += line_len + i;
143 + if ((i + line_len) == max_width)
145 + wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
146 + label_index = label_index + line_len + i;
150 + wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
155 + wrapped_label = malloc(sizeof(*wrapped_label));
156 + wrapped_label[0] = (char*)classification;
159 + for (n = 0; n < lines; n++ )
161 + printf("userdict/ESPp%c(", ('a' + n));
162 + for (ptr = wrapped_label[n], i = 0; *ptr; ptr ++, i++)
163 + if (*ptr < 32 || *ptr > 126)
164 + printf("\\%03o", *ptr);
167 + if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
170 + printf("%c", *ptr);
181 + * For LSPP use a fixed width font so that line wrapping can be calculated
184 + puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
187 + * Finally, the procedure to write the labels on the page...
190 + printf("userdict/ESPwl{\n"
191 + " ESPlf setfont\n");
192 + printf(" ESPp%c stringwidth pop dup 12 add exch -0.5 mul %.0f add\n ",
193 + 'a' + longest_line, width * 0.5f);
194 + for (n = 1; n < lines; n++)
196 + printf("\n 1 setgray\n");
197 + printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
198 + (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
199 + printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
200 + (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
201 + printf(" 0 setgray\n");
202 + printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
203 + (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
204 + printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
205 + (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
206 + for (n = 0; n < lines; n ++)
208 + printf(" dup %.0f moveto ESPp%c show\n",
209 + bottom + 6.0 + ((lines - (n+1)) * 16.0), 'a' + n);
210 + printf(" %.0f moveto ESPp%c show\n", top + 2.0 - ((n + 1) * 16.0), 'a' + n);
216 + * Do some clean up at the end of the LSPP special case
218 + free(wrapped_label);
223 +#endif /* !WITH_LSPP */
226 * Set the classification + page label string...
228 @@ -401,7 +537,10 @@ WriteLabelProlog(const char *label, /* I
229 printf(" %.0f moveto ESPpl show\n", top - 14.0);
235 +#endif /* WITH_LSPP */
239 diff -up cups-2.2b2/filter/pstops.c.lspp cups-2.2b2/filter/pstops.c
240 --- cups-2.2b2/filter/pstops.c.lspp 2016-06-24 17:43:35.000000000 +0200
241 +++ cups-2.2b2/filter/pstops.c 2016-06-27 17:39:48.077973863 +0200
242 @@ -3176,6 +3176,18 @@ write_label_prolog(pstops_doc_t *doc, /*
244 const char *classification; /* CLASSIFICATION environment variable */
245 const char *ptr; /* Temporary string pointer */
247 + int i, /* counter */
249 + lines, /* number of lines needed */
250 + line_len, /* index into tmp_label */
251 + label_len, /* length of the label in characters */
252 + label_index, /* index into the label */
253 + longest, /* length of the longest line */
254 + longest_line, /* index to the longest line */
255 + max_width; /* maximum width in characters */
256 + char **wrapped_label; /* label with line breaks */
257 +#endif /* WITH_LSPP */
261 @@ -3198,6 +3210,124 @@ write_label_prolog(pstops_doc_t *doc, /*
266 + if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
269 + * Based on the 12pt fixed width font below determine the max_width
271 + max_width = width / 8;
274 + classification += 5; // Skip the "LSPP:"
275 + label_len = strlen(classification);
277 + if (label_len > max_width)
279 + lines = 1 + (int)(label_len / max_width);
280 + line_len = (int)(label_len / lines);
281 + wrapped_label = malloc(sizeof(*wrapped_label) * lines);
282 + label_index = i = n = 0;
283 + while (classification[label_index])
285 + if ((label_index + line_len) > label_len)
287 + switch (classification[label_index + line_len + i])
293 + wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
294 + label_index += line_len + i;
301 + if ((i + line_len) == max_width)
303 + wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
304 + label_index = label_index + line_len + i;
308 + wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
313 + wrapped_label = malloc(sizeof(*wrapped_label));
314 + wrapped_label[0] = (char*)classification;
317 + for (n = 0; n < lines; n++ )
319 + printf("userdict/ESPp%c(", ('a' + n));
320 + for (ptr = wrapped_label[n], i = 0; *ptr; ptr ++, i++)
321 + if (*ptr < 32 || *ptr > 126)
322 + printf("\\%03o", *ptr);
325 + if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
328 + printf("%c", *ptr);
339 + * For LSPP use a fixed width font so that line wrapping can be calculated
342 + puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
345 + * Finally, the procedure to write the labels on the page...
348 + printf("userdict/ESPwl{\n"
349 + " ESPlf setfont\n");
350 + printf(" ESPp%c stringwidth pop dup 12 add exch -0.5 mul %.0f add\n ",
351 + 'a' + longest_line, width * 0.5f);
352 + for (n = 1; n < lines; n++)
354 + printf("\n 1 setgray\n");
355 + printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
356 + (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
357 + printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
358 + (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
359 + printf(" 0 setgray\n");
360 + printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
361 + (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
362 + printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
363 + (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
364 + for (n = 0; n < lines; n ++)
366 + printf(" dup %.0f moveto ESPp%c show\n",
367 + bottom + 6.0 + ((lines - (n+1)) * 16.0), 'a' + n);
368 + printf(" %.0f moveto ESPp%c show\n", top + 2.0 - ((n + 1) * 16.0), 'a' + n);
374 + * Do some clean up at the end of the LSPP special case
376 + free(wrapped_label);
381 +#endif /* !WITH_LSPP */
384 * Set the classification + page label string...
386 @@ -3276,7 +3406,10 @@ write_label_prolog(pstops_doc_t *doc, /*
387 doc_printf(doc, " %.0f moveto ESPpl show\n", top - 14.0);
388 doc_puts(doc, "pop\n");
389 doc_puts(doc, "}bind put\n");
393 +#endif /* WITH_LSPP */
397 diff -up cups-2.2b2/Makedefs.in.lspp cups-2.2b2/Makedefs.in
398 --- cups-2.2b2/Makedefs.in.lspp 2016-06-27 17:39:48.045974117 +0200
399 +++ cups-2.2b2/Makedefs.in 2016-06-27 17:39:48.077973863 +0200
400 @@ -143,7 +143,7 @@ LDFLAGS = -L../cgi-bin -L../cups -L../f
401 @LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM)
402 LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(DNSSDLIBS) $(LIBZ)
403 LINKCUPSIMAGE = @LINKCUPSIMAGE@
404 -LIBS = $(LINKCUPS) $(COMMONLIBS)
405 +LIBS = $(LINKCUPS) $(COMMONLIBS) @LIBAUDIT@ @LIBSELINUX@
406 ONDEMANDFLAGS = @ONDEMANDFLAGS@
407 ONDEMANDLIBS = @ONDEMANDLIBS@
409 diff -up cups-2.2b2/scheduler/client.c.lspp cups-2.2b2/scheduler/client.c
410 --- cups-2.2b2/scheduler/client.c.lspp 2016-06-24 17:43:35.000000000 +0200
411 +++ cups-2.2b2/scheduler/client.c 2016-06-27 17:39:48.077973863 +0200
413 #define _HTTP_NO_PRIVATE
418 +#endif /* !defined(_GNU_SOURCE) */
420 # include <libproc.h>
421 #endif /* __APPLE__ */
424 #endif /* HAVE_TCPD_H */
426 +# include <selinux/selinux.h>
427 +# include <selinux/context.h>
429 +#endif /* WITH_LSPP */
433 @@ -266,6 +274,59 @@ cupsdAcceptClient(cupsd_listener_t *lis)
435 #endif /* HAVE_TCPD_H */
438 + if (is_lspp_config())
441 + unsigned int cl=sizeof(cr);
443 + if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &cr, &cl) == 0)
446 + * client_pid_to_auid() can be racey
447 + * In this case the pid is based on a socket connected to the client
449 + if ((con->auid = client_pid_to_auid(cr.pid)) == -1)
451 + httpClose(con->http);
452 + cupsdLogClient(con, CUPSD_LOG_ERROR,
453 + "Unable to determine client auid for client pid=%d",
458 + cupsdLogClient(con, CUPSD_LOG_INFO,
459 + "peer's pid=%d, uid=%d, gid=%d, auid=%d",
460 + cr.pid, cr.uid, cr.gid, con->auid);
464 + httpClose(con->http);
465 + cupsdLogClient(con, CUPSD_LOG_ERROR, "getsockopt() failed");
471 + * get the context of the peer connection
473 + if (getpeercon(httpGetFd(con->http), &con->scon))
475 + httpClose(con->http);
476 + cupsdLogClient(con, CUPSD_LOG_ERROR, "getpeercon() failed");
481 + cupsdLogClient(con, CUPSD_LOG_INFO, "client context=%s", con->scon);
485 + cupsdLogClient(con, CUPSD_LOG_DEBUG, "skipping getpeercon()");
486 + cupsdSetString(&con->scon, UNKNOWN_SL);
488 +#endif /* WITH_LSPP */
491 if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
493 @@ -560,6 +621,13 @@ cupsdReadClient(cupsd_client_t *con) /*
494 mime_type_t *type; /* MIME type of file */
495 cupsd_printer_t *p; /* Printer */
496 static unsigned request_id = 0; /* Request ID for temp files */
498 + security_context_t spoolcon; /* context of the job file */
499 + context_t clicon; /* contex_t container for con->scon */
500 + context_t tmpcon; /* temp context to swap the level */
501 + char *clirange; /* SELinux sensitivity range */
502 + char *cliclearance; /* SELinux low end clearance */
503 +#endif /* WITH_LSPP */
506 status = HTTP_STATUS_CONTINUE;
507 @@ -1924,6 +1992,73 @@ cupsdReadClient(cupsd_client_t *con) /*
508 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
512 + if (strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
514 + if (getfilecon(con->filename, &spoolcon) == -1)
516 + cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
517 + cupsdCloseClient(con);
520 + clicon = context_new(con->scon);
521 + tmpcon = context_new(spoolcon);
523 + if (!clicon || !tmpcon)
525 + cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
527 + context_free(clicon);
529 + context_free(tmpcon);
530 + cupsdCloseClient(con);
533 + clirange = (char *) context_range_get(clicon);
536 + clirange = strdup(clirange);
537 + if ((cliclearance = strtok(clirange, "-")) != NULL)
539 + if (context_range_set(tmpcon, cliclearance) == -1)
541 + cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
543 + context_free(tmpcon);
544 + context_free(clicon);
545 + cupsdCloseClient(con);
551 + if (context_range_set(tmpcon, (context_range_get(clicon))) == -1)
553 + cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
555 + context_free(tmpcon);
556 + context_free(clicon);
557 + cupsdCloseClient(con);
563 + if (setfilecon(con->filename, context_str(tmpcon)) == -1)
565 + cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
566 + context_free(tmpcon);
567 + context_free(clicon);
568 + cupsdCloseClient(con);
571 + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "%s set to %s",
572 + con->filename, context_str(tmpcon));
573 + context_free(tmpcon);
574 + context_free(clicon);
576 +#endif /* WITH_LSPP */
578 if (httpGetState(con->http) != HTTP_STATE_POST_SEND)
580 if (!httpWait(con->http, 0))
581 @@ -3456,6 +3591,49 @@ is_path_absolute(const char *path) /* I
587 + * 'client_pid_to_auid()' - Using the client's pid, read /proc and determine the loginuid.
590 +uid_t client_pid_to_auid(pid_t clipid)
594 + char buf[16] = {0};
595 + char fname[32] = {0};
599 + * Hopefully this pid is still the one we are interested in.
601 + snprintf(fname, 32, "/proc/%d/loginuid", clipid);
602 + in = open(fname, O_NOFOLLOW|O_RDONLY);
610 + len = read(in, buf, sizeof(buf));
611 + } while (len < 0 && errno == EINTR);
615 + if (len < 0 || len >= sizeof(buf))
620 + uid = strtol(buf, 0, 10);
627 +#endif /* WITH_LSPP */
630 * 'pipe_command()' - Pipe the output of a command to the remote client.
631 diff -up cups-2.2b2/scheduler/client.h.lspp cups-2.2b2/scheduler/client.h
632 --- cups-2.2b2/scheduler/client.h.lspp 2016-06-24 17:43:35.000000000 +0200
633 +++ cups-2.2b2/scheduler/client.h 2016-06-27 17:39:48.077973863 +0200
635 #endif /* HAVE_AUTHORIZATION_H */
638 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
639 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
642 +#include <selinux/selinux.h>
643 +#endif /* WITH_LSPP */
646 * HTTP client structure...
648 @@ -65,6 +72,10 @@ struct cupsd_client_s
649 #ifdef HAVE_AUTHORIZATION_H
650 AuthorizationRef authref; /* Authorization ref */
651 #endif /* HAVE_AUTHORIZATION_H */
653 + security_context_t scon; /* Security context of connection */
654 + uid_t auid; /* Audit loginuid of the client */
655 +#endif /* WITH_LSPP */
658 #define HTTP(con) ((con)->http)
659 @@ -138,6 +149,9 @@ extern void cupsdStartListening(void);
660 extern void cupsdStopListening(void);
661 extern void cupsdUpdateCGI(void);
662 extern void cupsdWriteClient(cupsd_client_t *con);
664 +extern uid_t client_pid_to_auid(pid_t clipid);
665 +#endif /* WITH_LSPP */
668 extern int cupsdEndTLS(cupsd_client_t *con);
669 diff -up cups-2.2b2/scheduler/conf.c.lspp cups-2.2b2/scheduler/conf.c
670 --- cups-2.2b2/scheduler/conf.c.lspp 2016-06-27 17:39:48.072973903 +0200
671 +++ cups-2.2b2/scheduler/conf.c 2016-06-27 17:39:48.078973855 +0200
673 # define INADDR_NONE 0xffffffff
674 #endif /* !INADDR_NONE */
677 +# include <libaudit.h>
678 +#endif /* WITH_LSPP */
681 * Configuration variable structure...
682 @@ -131,6 +134,10 @@ static const cupsd_var_t cupsd_vars[] =
683 { "ServerName", &ServerName, CUPSD_VARTYPE_STRING },
684 { "StrictConformance", &StrictConformance, CUPSD_VARTYPE_BOOLEAN },
685 { "Timeout", &Timeout, CUPSD_VARTYPE_TIME },
687 + { "AuditLog", &AuditLog, CUPSD_VARTYPE_INTEGER },
688 + { "PerPageLabels", &PerPageLabels, CUPSD_VARTYPE_BOOLEAN },
689 +#endif /* WITH_LSPP */
690 { "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN }
692 static const cupsd_var_t cupsfiles_vars[] =
693 @@ -577,6 +584,9 @@ cupsdReadConfiguration(void)
694 const char *tmpdir; /* TMPDIR environment variable */
695 struct stat tmpinfo; /* Temporary directory info */
696 cupsd_policy_t *p; /* Policy */
698 + char *audit_message; /* Audit message string */
699 +#endif /* WITH_LSPP */
703 @@ -931,6 +941,25 @@ cupsdReadConfiguration(void)
708 + if (AuditLog != -1)
711 + * ClassifyOverride is set during read_configuration, if its ON, report it now
713 + if (ClassifyOverride)
714 + audit_log_user_message(AuditLog, AUDIT_USYS_CONFIG,
715 + "[Config] ClassifyOverride=enabled Users can override print banners",
716 + ServerName, NULL, NULL, 1);
718 + * PerPageLabel is set during read_configuration, if its OFF, report it now
720 + if (!PerPageLabels)
721 + audit_log_user_message(AuditLog, AUDIT_USYS_CONFIG,
722 + "[Config] PerPageLabels=disabled", ServerName, NULL, NULL, 1);
724 +#endif /* WITH_LSPP */
726 cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
727 RemotePort ? "enabled" : "disabled");
729 @@ -1350,7 +1379,19 @@ cupsdReadConfiguration(void)
730 cupsdClearString(&Classification);
734 cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
736 + if (AuditLog != -1)
738 + audit_message = NULL;
739 + cupsdSetStringf(&audit_message, "[Config] Classification=%s", Classification);
740 + audit_log_user_message(AuditLog, AUDIT_LABEL_LEVEL_CHANGE, audit_message,
741 + ServerName, NULL, NULL, 1);
742 + cupsdClearString(&audit_message);
744 +#endif /* WITH_LSPP */
748 * Check the MaxClients setting, and then allocate memory for it...
749 @@ -3827,6 +3868,18 @@ read_location(cups_file_t *fp, /* I - C
750 return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
754 +int is_lspp_config()
756 + if (Classification != NULL)
757 + return ((_cups_strcasecmp(Classification, MLS_CONFIG) == 0)
758 + || (_cups_strcasecmp(Classification, TE_CONFIG) == 0)
759 + || (_cups_strcasecmp(Classification, SELINUX_CONFIG) == 0));
763 +#endif /* WITH_LSPP */
767 * 'read_policy()' - Read a <Policy name> definition.
768 diff -up cups-2.2b2/scheduler/conf.h.lspp cups-2.2b2/scheduler/conf.h
769 --- cups-2.2b2/scheduler/conf.h.lspp 2016-06-27 17:39:48.078973855 +0200
770 +++ cups-2.2b2/scheduler/conf.h 2016-06-27 17:44:46.370632333 +0200
771 @@ -248,6 +248,13 @@ VAR char *ServerKeychain VALUE(NULL);
772 /* Keychain holding cert + key */
773 #endif /* HAVE_SSL */
776 +VAR int AuditLog VALUE(-1),
777 + /* File descriptor for audit */
778 + PerPageLabels VALUE(TRUE);
779 + /* Put the label on each page */
780 +#endif /* WITH_LSPP */
783 VAR int IdleExitTimeout VALUE(60);
784 /* Time after which an idle cupsd will exit */
785 @@ -266,6 +273,9 @@ VAR int HaveServerCreds VALUE(0);
786 VAR gss_cred_id_t ServerCreds; /* Server's GSS credentials */
787 #endif /* HAVE_GSSAPI */
790 +extern int is_lspp_config(void);
791 +#endif /* WITH_LSPP */
795 diff -up cups-2.2b2/scheduler/cupsd.h.lspp cups-2.2b2/scheduler/cupsd.h
796 --- cups-2.2b2/scheduler/cupsd.h.lspp 2016-06-27 17:39:48.064973966 +0200
797 +++ cups-2.2b2/scheduler/cupsd.h 2016-06-27 17:39:48.078973855 +0200
799 * file is missing or damaged, see the license at "http://www.cups.org/".
802 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
803 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
806 * Include necessary headers.
813 +# define MLS_CONFIG "mls"
814 +# define TE_CONFIG "te"
815 +# define SELINUX_CONFIG "SELinux"
816 +# define UNKNOWN_SL "UNKNOWN SL"
817 +#endif /* WITH_LSPP */
821 #if defined(HAVE_CDSASSL)
822 # include <CoreFoundation/CoreFoundation.h>
823 #endif /* HAVE_CDSASSL */
827 * Some OS's don't have hstrerror(), most notably Solaris...
829 diff -up cups-2.2b2/scheduler/ipp.c.lspp cups-2.2b2/scheduler/ipp.c
830 --- cups-2.2b2/scheduler/ipp.c.lspp 2016-06-27 17:39:48.028974252 +0200
831 +++ cups-2.2b2/scheduler/ipp.c 2016-06-27 17:39:48.080973839 +0200
833 * file is missing or damaged, see the license at "http://www.cups.org/".
836 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
837 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
840 * Include necessary headers...
842 @@ -37,6 +40,14 @@ extern int mbr_check_membership_by_id(uu
843 # endif /* HAVE_MEMBERSHIPPRIV_H */
844 #endif /* __APPLE__ */
847 +#include <libaudit.h>
848 +#include <selinux/selinux.h>
849 +#include <selinux/context.h>
850 +#include <selinux/avc.h>
851 +#include <selinux/flask.h>
852 +#include <selinux/av_permissions.h>
853 +#endif /* WITH_LSPP */
857 @@ -61,6 +72,9 @@ static void cancel_all_jobs(cupsd_client
858 static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
859 static void cancel_subscription(cupsd_client_t *con, int id);
860 static int check_rss_recipient(const char *recipient);
862 +static int check_context(cupsd_client_t *con, cupsd_job_t *job);
863 +#endif /* WITH_LSPP */
864 static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
865 static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
866 static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
867 @@ -1248,6 +1262,21 @@ add_job(cupsd_client_t *con, /* I - Cl
872 + char *audit_message; /* Audit message string */
873 + char *printerfile; /* device file pointed to by the printer */
874 + char *userheader = NULL; /* User supplied job-sheets[0] */
875 + char *userfooter = NULL; /* User supplied job-sheets[1] */
876 + int override = 0; /* Was a banner overrode on a job */
877 + security_id_t clisid; /* SELinux SID for the client */
878 + security_id_t psid; /* SELinux SID for the printer */
879 + context_t printercon; /* Printer's context string */
880 + struct stat printerstat; /* Printer's stat buffer */
881 + security_context_t devcon; /* Printer's SELinux context */
882 + struct avc_entry_ref avcref; /* Pointer to the access vector cache */
883 + security_class_t tclass; /* Object class for the SELinux check */
884 + access_vector_t avr; /* Access method being requested */
885 +#endif /* WITH_LSPP */
888 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
889 @@ -1559,6 +1588,106 @@ add_job(cupsd_client_t *con, /* I - Cl
894 + if (is_lspp_config())
896 + if (!con->scon || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
898 + cupsdLogMessage(CUPSD_LOG_ERROR, "add_job: missing classification for connection \'%s\'!", printer->name);
899 + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Missing required security attributes."));
904 + * Perform an access check so that if the user gets feedback at enqueue time
907 + printerfile = strstr(printer->device_uri, "/dev/");
908 + if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
909 + printerfile = printer->device_uri + strlen("file:");
911 + if (printerfile != NULL)
913 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: Attempting an access check on printer device %s",
916 + if (lstat(printerfile, &printerstat) < 0)
918 + if (errno != ENOENT)
920 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to stat the printer"));
924 + * The printer does not exist, so for now assume it's a FileDevice
926 + tclass = SECCLASS_FILE;
929 + else if (S_ISCHR(printerstat.st_mode))
931 + tclass = SECCLASS_CHR_FILE;
932 + avr = CHR_FILE__WRITE;
934 + else if (S_ISREG(printerstat.st_mode))
936 + tclass = SECCLASS_FILE;
941 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Printer is not a character device or regular file"));
944 + static int avc_initialized = 0;
945 + if (!avc_initialized++)
946 + avc_init("cupsd_enqueue_", NULL, NULL, NULL, NULL);
947 + avc_entry_ref_init(&avcref);
948 + if (avc_context_to_sid(con->scon, &clisid) != 0)
950 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the client"));
953 + if (getfilecon(printerfile, &devcon) == -1)
955 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux context of the printer"));
958 + printercon = context_new(devcon);
959 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: printer context %s client context %s",
960 + context_str(printercon), con->scon);
961 + context_free(printercon);
963 + if (avc_context_to_sid(devcon, &psid) != 0)
965 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the printer"));
970 + if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
973 + * The access check failed, so cancel the job and send an audit message
975 + if (AuditLog != -1)
977 + audit_message = NULL;
978 + cupsdSetStringf(&audit_message, "job=? auid=%u acct=%s obj=%s refused"
979 + " unable to access printer=%s", con->auid,
980 + con->username, con->scon, printer->name);
981 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
982 + ServerName, NULL, NULL, 0);
983 + cupsdClearString(&audit_message);
986 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("SELinux prohibits access to the printer"));
991 +#endif /* WITH_LSPP */
993 if ((job = cupsdAddJob(priority, printer->name)) == NULL)
995 send_ipp_status(con, IPP_INTERNAL_ERROR,
996 @@ -1567,6 +1696,32 @@ add_job(cupsd_client_t *con, /* I - Cl
1001 + if (is_lspp_config())
1004 + * duplicate the security context and auid of the connection into the job structure
1006 + job->scon = strdup(con->scon);
1007 + job->auid = con->auid;
1010 + * add the security context to the request so that on a restart the security
1011 + * attributes will be able to be restored
1013 + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "security-context",
1019 + * Fill in the security context of the job as unlabeled
1021 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: setting context of job to %s", UNKNOWN_SL);
1022 + cupsdSetString(&job->scon, UNKNOWN_SL);
1024 +#endif /* WITH_LSPP */
1026 job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
1027 job->attrs = con->request;
1029 @@ -1756,6 +1911,29 @@ add_job(cupsd_client_t *con, /* I - Cl
1030 ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
1031 ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
1037 + * The option was present, so capture the user supplied strings
1039 + userheader = strdup(attr->values[0].string.text);
1041 + if (attr->num_values > 1)
1042 + userfooter = strdup(attr->values[1].string.text);
1044 + if (Classification != NULL && (strcmp(userheader, Classification) == 0)
1045 + && userfooter &&(strcmp(userfooter, Classification) == 0))
1048 + * Since both values are Classification, the user is not trying to Override
1051 + if (userfooter) free(userfooter);
1052 + userheader = userfooter = NULL;
1055 +#endif /* WITH_LSPP */
1057 job->job_sheets = attr;
1059 @@ -1786,6 +1964,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1060 "job-sheets=\"%s,none\", "
1061 "job-originating-user-name=\"%s\"",
1062 Classification, job->username);
1065 +#endif /* WITH_LSPP */
1067 else if (attr->num_values == 2 &&
1068 strcmp(attr->values[0].string.text,
1069 @@ -1804,6 +1985,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1070 "job-originating-user-name=\"%s\"",
1071 attr->values[0].string.text,
1072 attr->values[1].string.text, job->username);
1075 +#endif /* WITH_LSPP */
1077 else if (strcmp(attr->values[0].string.text, Classification) &&
1078 strcmp(attr->values[0].string.text, "none") &&
1079 @@ -1824,6 +2008,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1080 "job-originating-user-name=\"%s\"",
1081 attr->values[0].string.text,
1082 attr->values[1].string.text, job->username);
1085 +#endif /* WITH_LSPP */
1088 else if (strcmp(attr->values[0].string.text, Classification) &&
1089 @@ -1864,8 +2051,52 @@ add_job(cupsd_client_t *con, /* I - Cl
1090 "job-sheets=\"%s\", "
1091 "job-originating-user-name=\"%s\"",
1092 Classification, job->username);
1095 +#endif /* WITH_LSPP */
1098 + if (is_lspp_config() && AuditLog != -1)
1100 + audit_message = NULL;
1102 + if (userheader || userfooter)
1107 + * The user overrode the banner, so audit it
1109 + cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
1110 + " using banners=%s,%s", job->id, userheader,
1111 + userfooter, attr->values[0].string.text,
1112 + (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
1113 + audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
1114 + ServerName, NULL, NULL, 1);
1119 + * The user tried to override the banner, audit the failure
1121 + cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
1122 + " ignored banners=%s,%s", job->id, userheader,
1123 + userfooter, attr->values[0].string.text,
1124 + (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
1125 + audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
1126 + ServerName, NULL, NULL, 0);
1128 + cupsdClearString(&audit_message);
1136 +#endif /* WITH_LSPP */
1141 * See if we need to add the starting sheet...
1142 @@ -3619,6 +3850,128 @@ check_rss_recipient(
1148 + * 'check_context()' - Check SELinux security context of a user and job
1151 +static int /* O - 1 if OK, 0 if not, -1 on error */
1152 +check_context(cupsd_client_t *con, /* I - Client connection */
1153 + cupsd_job_t *job) /* I - Job */
1155 + int enforcing; /* is SELinux in enforcing mode */
1156 + char filename[1024]; /* Filename of the spool file */
1157 + security_id_t clisid; /* SELinux SID of the client */
1158 + security_id_t jobsid; /* SELinux SID of the job */
1159 + security_id_t filesid; /* SELinux SID of the spool file */
1160 + struct avc_entry_ref avcref; /* AVC entry cache pointer */
1161 + security_class_t tclass; /* SELinux security class */
1162 + access_vector_t avr; /* SELinux access being queried */
1163 + security_context_t spoolfilecon; /* SELinux context of the spool file */
1167 + * Validate the input to be sure there are contexts to work with...
1170 + if (con->scon == NULL || job->scon == NULL
1171 + || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0
1172 + || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
1175 + if ((enforcing = security_getenforce()) == -1)
1177 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1178 + "Error while determining SELinux enforcement");
1181 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1182 + "check_context: client context %s job context %s",
1183 + con->scon, job->scon);
1187 + * Initialize the avc engine...
1190 + static int avc_initialized = 0;
1191 + if (! avc_initialized++)
1193 + if (avc_init("cupsd", NULL, NULL, NULL, NULL) < 0)
1195 + cupsdLogJob(job, CUPSD_LOG_ERROR, "check_context: unable avc_init");
1199 + if (avc_context_to_sid(con->scon, &clisid) != 0)
1201 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1202 + "check_context: unable to convert %s to SELinux sid",
1206 + if (avc_context_to_sid(job->scon, &jobsid) != 0)
1208 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1209 + "check_context: unable to convert %s to SELinux sid",
1213 + avc_entry_ref_init(&avcref);
1214 + tclass = SECCLASS_FILE;
1218 + * Perform the check with the client as the subject, first with the job as the object
1219 + * if that fails then with the spool file as the object...
1222 + if (avc_has_perm_noaudit(clisid, jobsid, tclass, avr, &avcref, NULL) != 0)
1224 + cupsdLogJob(job, CUPSD_LOG_INFO,
1225 + "check_context: SELinux denied access "
1226 + "based on the client context");
1228 + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
1229 + if (getfilecon(filename, &spoolfilecon) == -1)
1231 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1232 + "check_context: Unable to get spoolfile context");
1235 + if (avc_context_to_sid(spoolfilecon, &filesid) != 0)
1237 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1238 + "check_context: Unable to determine the "
1239 + "SELinux sid for the spool file");
1240 + freecon(spoolfilecon);
1243 + freecon(spoolfilecon);
1244 + if (avc_has_perm_noaudit(clisid, filesid, tclass, avr, &avcref, NULL) != 0)
1246 + cupsdLogJob(job, CUPSD_LOG_INFO,
1247 + "check_context: SELinux denied access to the spool file");
1250 + cupsdLogJob(job, CUPSD_LOG_INFO,
1251 + "check_context: SELinux allowed access to the spool file");
1255 + if (enforcing == 0)
1256 + cupsdLogJob(job, CUPSD_LOG_INFO,
1257 + "check_context: allowing operation due to permissive mode");
1259 + cupsdLogJob(job, CUPSD_LOG_INFO,
1260 + "check_context: SELinux allowed access based on the "
1261 + "client context");
1265 +#endif /* WITH_LSPP */
1269 * 'check_quotas()' - Check quotas for a printer and user.
1271 @@ -4075,6 +4428,15 @@ copy_banner(cupsd_client_t *con, /* I -
1272 char attrname[255], /* Name of attribute */
1273 *s; /* Pointer into name */
1274 ipp_attribute_t *attr; /* Attribute */
1276 + const char *mls_label; /* SL of print job */
1277 + char *jobrange; /* SELinux sensitivity range */
1278 + char *jobclearance; /* SELinux low end clearance */
1279 + context_t jobcon; /* SELinux context of the job */
1280 + context_t tmpcon; /* Temp context to set the level */
1281 + security_context_t spoolcon; /* Context of the file in the spool */
1282 +#endif /* WITH_LSPP */
1286 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1287 @@ -4110,6 +4472,85 @@ copy_banner(cupsd_client_t *con, /* I -
1289 fchmod(cupsFileNumber(out), 0640);
1290 fchown(cupsFileNumber(out), RunUser, Group);
1292 + if (job->scon != NULL &&
1293 + strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1295 + if (getfilecon(filename, &spoolcon) == -1)
1297 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1298 + "Unable to get the context of the banner file %s - %s",
1299 + filename, strerror(errno));
1300 + job->num_files --;
1303 + tmpcon = context_new(spoolcon);
1304 + jobcon = context_new(job->scon);
1305 + freecon(spoolcon);
1306 + if (!tmpcon || !jobcon)
1309 + context_free(tmpcon);
1311 + context_free(jobcon);
1312 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1313 + "copy_banner: Unable to get the SELinux contexts");
1314 + job->num_files --;
1317 + jobrange = (char *) context_range_get(jobcon);
1320 + jobrange = strdup(jobrange);
1321 + if ((jobclearance = strtok(jobrange, "-")) != NULL)
1323 + if (context_range_set(tmpcon, jobclearance) == -1)
1325 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1326 + "copy_banner: Unable to set the "
1327 + "level of the context for file %s - %s",
1328 + filename, strerror(errno));
1330 + context_free(jobcon);
1331 + context_free(tmpcon);
1332 + job->num_files --;
1338 + if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1340 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1341 + "copy_banner: Unable to set the "
1342 + "level of the context for file %s - %s",
1343 + filename, strerror(errno));
1345 + context_free(jobcon);
1346 + context_free(tmpcon);
1347 + job->num_files --;
1353 + if (setfilecon(filename, context_str(tmpcon)) == -1)
1355 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1356 + "copy_banner: Unable to set the "
1357 + "context of the banner file %s - %s",
1358 + filename, strerror(errno));
1359 + context_free(jobcon);
1360 + context_free(tmpcon);
1361 + job->num_files --;
1364 + cupsdLogJob(job, CUPSD_LOG_DEBUG2, "copy_banner: %s set to %s",
1365 + filename, context_str(tmpcon));
1366 + context_free(jobcon);
1367 + context_free(tmpcon);
1369 +#endif /* WITH_LSPP */
1372 * Try the localized banner file under the subdirectory...
1373 @@ -4204,6 +4645,24 @@ copy_banner(cupsd_client_t *con, /* I -
1378 + if (strcmp(s, "mls-label") == 0)
1380 + if (job->scon != NULL && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1382 + jobcon = context_new(job->scon);
1383 + if (_cups_strcasecmp(name, MLS_CONFIG) == 0)
1384 + mls_label = context_range_get(jobcon);
1385 + else if (_cups_strcasecmp(name, TE_CONFIG) == 0)
1386 + mls_label = context_type_get(jobcon);
1387 + else // default to using the whole context string
1388 + mls_label = context_str(jobcon);
1389 + cupsFilePuts(out, mls_label);
1390 + context_free(jobcon);
1394 +#endif /* WITH_LSPP */
1395 if (!strcmp(s, "printer-name"))
1397 cupsFilePuts(out, job->dest);
1398 @@ -6389,6 +6848,22 @@ get_job_attrs(cupsd_client_t *con, /* I
1400 exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
1405 + * Check SELinux...
1407 + if (is_lspp_config() && check_context(con, job) != 1)
1410 + * Unfortunately we have to lie to the user...
1412 + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
1415 +#endif /* WITH_LSPP */
1419 * Copy attributes...
1421 @@ -6786,6 +7261,11 @@ get_jobs(cupsd_client_t *con, /* I - C
1422 if (username[0] && _cups_strcasecmp(username, job->username))
1426 + if (is_lspp_config() && check_context(con, job) != 1)
1428 +#endif /* WITH_LSPP */
1431 ippAddSeparator(con->response);
1433 @@ -11415,6 +11895,11 @@ validate_user(cupsd_job_t *job, /* I
1435 strlcpy(username, get_username(con), userlen);
1438 + if (is_lspp_config() && check_context(con, job) != 1)
1440 +#endif /* WITH_LSPP */
1443 * Check the username against the owner...
1445 diff -up cups-2.2b2/scheduler/job.c.lspp cups-2.2b2/scheduler/job.c
1446 --- cups-2.2b2/scheduler/job.c.lspp 2016-06-27 17:39:48.041974149 +0200
1447 +++ cups-2.2b2/scheduler/job.c 2016-06-27 17:39:48.081973831 +0200
1449 * file is missing or damaged, see the license at "http://www.cups.org/".
1452 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1453 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1456 * Include necessary headers...
1459 # endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
1460 #endif /* __APPLE__ */
1463 +#include <libaudit.h>
1464 +#include <selinux/selinux.h>
1465 +#include <selinux/context.h>
1466 +#include <selinux/avc.h>
1467 +#include <selinux/flask.h>
1468 +#include <selinux/av_permissions.h>
1469 +#endif /* WITH_LSPP */
1472 * Design Notes for Job Management
1473 @@ -546,6 +557,14 @@ cupsdContinueJob(cupsd_job_t *job) /* I
1474 /* PRINTER_STATE_REASONS env var */
1476 /* RIP_MAX_CACHE env variable */
1478 + char *audit_message = NULL; /* Audit message string */
1479 + context_t jobcon; /* SELinux context of the job */
1480 + char *label_template = NULL; /* SL to put in classification
1482 + const char *mls_label = NULL; /* SL to put in classification
1484 +#endif /* WITH_LSPP */
1487 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1488 @@ -1082,6 +1101,67 @@ cupsdContinueJob(cupsd_job_t *job) /* I
1489 if (final_content_type[0])
1490 envp[envc ++] = final_content_type;
1493 + if (is_lspp_config())
1495 + if (!job->scon || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
1497 + if (AuditLog != -1)
1499 + audit_message = NULL;
1500 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s",
1501 + job->id, job->auid, job->username, job->printer->name, title);
1502 + audit_log_user_message(AuditLog, AUDIT_USER_UNLABELED_EXPORT, audit_message,
1503 + ServerName, NULL, NULL, 1);
1504 + cupsdClearString(&audit_message);
1509 + jobcon = context_new(job->scon);
1511 + if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME)) == NULL)
1512 + label_template = strdup(Classification);
1513 + else if (attr->num_values > 1 &&
1514 + strcmp(attr->values[1].string.text, "none") != 0)
1515 + label_template = strdup(attr->values[1].string.text);
1517 + label_template = strdup(attr->values[0].string.text);
1519 + if (_cups_strcasecmp(label_template, MLS_CONFIG) == 0)
1520 + mls_label = context_range_get(jobcon);
1521 + else if (_cups_strcasecmp(label_template, TE_CONFIG) == 0)
1522 + mls_label = context_type_get(jobcon);
1523 + else if (_cups_strcasecmp(label_template, SELINUX_CONFIG) == 0)
1524 + mls_label = context_str(jobcon);
1526 + mls_label = label_template;
1528 + if (mls_label && (PerPageLabels || banner_page))
1530 + snprintf(classification, sizeof(classification), "CLASSIFICATION=LSPP:%s", mls_label);
1531 + envp[envc ++] = classification;
1534 + if ((AuditLog != -1) && !banner_page)
1536 + audit_message = NULL;
1537 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s"
1538 + " obj=%s label=%s", job->id, job->auid, job->username,
1539 + job->printer->name, title, job->scon, mls_label?mls_label:"none");
1540 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
1541 + ServerName, NULL, NULL, 1);
1542 + cupsdClearString(&audit_message);
1544 + context_free(jobcon);
1545 + free(label_template);
1550 + * Fall through to the non-LSPP behavior
1552 +#endif /* WITH_LSPP */
1553 if (Classification && !banner_page)
1555 if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1556 @@ -1905,6 +1985,22 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J
1557 ippSetString(job->attrs, &job->reasons, 0, "none");
1561 + if ((attr = ippFindAttribute(job->attrs, "security-context", IPP_TAG_NAME)) != NULL)
1562 + cupsdSetString(&job->scon, attr->values[0].string.text);
1563 + else if (is_lspp_config())
1566 + * There was no security context so delete the job
1568 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1569 + "Missing or bad security-context attribute "
1570 + "in control file \"%s\"!",
1574 +#endif /* WITH_LSPP */
1576 job->impressions = ippFindAttribute(job->attrs, "job-impressions-completed", IPP_TAG_INTEGER);
1577 job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER);
1578 job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
1579 @@ -2318,6 +2414,14 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
1581 char filename[1024]; /* Job control filename */
1582 cups_file_t *fp; /* Job file */
1584 + security_context_t spoolcon; /* context of the job control file */
1585 + context_t jobcon; /* contex_t container for job->scon */
1586 + context_t tmpcon; /* Temp context to swap the level */
1587 + char *jobclearance; /* SELinux low end clearance */
1588 + const char *jobrange; /* SELinux sensitivity range */
1589 + char *jobrange_copy; /* SELinux sensitivity range */
1590 +#endif /* WITH_LSPP */
1593 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
1594 @@ -2340,6 +2444,78 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
1596 fchown(cupsFileNumber(fp), RunUser, Group);
1599 + if (job->scon && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1601 + if (getfilecon(filename, &spoolcon) == -1)
1603 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1604 + "Unable to get context of job control file \"%s\" - %s.",
1605 + filename, strerror(errno));
1608 + jobcon = context_new(job->scon);
1609 + tmpcon = context_new(spoolcon);
1610 + freecon(spoolcon);
1611 + if (!jobcon || !tmpcon)
1614 + context_free(jobcon);
1616 + context_free(tmpcon);
1617 + cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to get SELinux contexts");
1620 + jobrange = context_range_get(jobcon);
1623 + jobrange_copy = strdup(jobrange);
1624 + if ((jobclearance = strtok(jobrange_copy, "-")) != NULL)
1626 + if (context_range_set(tmpcon, jobclearance) == -1)
1628 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1629 + "Unable to set the range for "
1630 + "job control file \"%s\" - %s.",
1631 + filename, strerror(errno));
1632 + free(jobrange_copy);
1633 + context_free(tmpcon);
1634 + context_free(jobcon);
1640 + if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1642 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1643 + "Unable to set the range for "
1644 + "job control file \"%s\" - %s.",
1645 + filename, strerror(errno));
1646 + free(jobrange_copy);
1647 + context_free(tmpcon);
1648 + context_free(jobcon);
1652 + free(jobrange_copy);
1654 + if (setfilecon(filename, context_str(tmpcon)) == -1)
1656 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1657 + "Unable to set context of job control file \"%s\" - %s.",
1658 + filename, strerror(errno));
1659 + context_free(tmpcon);
1660 + context_free(jobcon);
1663 + cupsdLogJob(job, CUPSD_LOG_DEBUG2, "New spool file context=%s",
1664 + context_str(tmpcon));
1665 + context_free(tmpcon);
1666 + context_free(jobcon);
1668 +#endif /* WITH_LSPP */
1670 job->attrs->state = IPP_IDLE;
1672 if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
1673 @@ -3919,6 +4095,19 @@ get_options(cupsd_job_t *job, /* I - Jo
1679 + * In LSPP mode refuse to honor the page-label
1681 + if (is_lspp_config() &&
1682 + !strcmp(attr->name, "page-label"))
1684 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1685 + "Ignoring page-label option due to LSPP mode");
1688 +#endif /* WITH_LSPP */
1691 * Otherwise add them to the list...
1693 @@ -4680,6 +4869,18 @@ start_job(cupsd_job_t *job, /* I -
1694 cupsd_printer_t *printer) /* I - Printer to print job */
1696 const char *filename; /* Support filename */
1698 + char *audit_message = NULL; /* Audit message string */
1699 + char *printerfile = NULL; /* Device file pointed to by the printer */
1700 + security_id_t clisid; /* SELinux SID for the client */
1701 + security_id_t psid; /* SELinux SID for the printer */
1702 + context_t printercon; /* Printer's context string */
1703 + struct stat printerstat; /* Printer's stat buffer */
1704 + security_context_t devcon; /* Printer's SELinux context */
1705 + struct avc_entry_ref avcref; /* Pointer to the access vector cache */
1706 + security_class_t tclass; /* Object class for the SELinux check */
1707 + access_vector_t avr; /* Access method being requested */
1708 +#endif /* WITH_LSPP */
1709 ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
1712 @@ -4856,6 +5057,113 @@ start_job(cupsd_job_t *job, /* I -
1713 fcntl(job->side_pipes[1], F_SETFD,
1714 fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
1717 + if (is_lspp_config())
1720 + * Perform an access check before printing, but only if the printer starts with /dev/
1722 + printerfile = strstr(printer->device_uri, "/dev/");
1723 + if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
1724 + printerfile = printer->device_uri + strlen("file:");
1726 + if (printerfile != NULL)
1728 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1729 + "Attempting to check access on printer device %s",
1731 + if (lstat(printerfile, &printerstat) < 0)
1733 + if (errno != ENOENT)
1735 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1736 + "Unable to stat the printer");
1737 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1741 + * The printer does not exist, so for now assume it's a FileDevice
1743 + tclass = SECCLASS_FILE;
1744 + avr = FILE__WRITE;
1746 + else if (S_ISCHR(printerstat.st_mode))
1748 + tclass = SECCLASS_CHR_FILE;
1749 + avr = CHR_FILE__WRITE;
1751 + else if (S_ISREG(printerstat.st_mode))
1753 + tclass = SECCLASS_FILE;
1754 + avr = FILE__WRITE;
1758 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1759 + "StartJob: Printer is not a character device or "
1761 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1764 + static int avc_initialized = 0;
1765 + if (!avc_initialized++)
1766 + avc_init("cupsd_dequeue_", NULL, NULL, NULL, NULL);
1767 + avc_entry_ref_init(&avcref);
1768 + if (avc_context_to_sid(job->scon, &clisid) != 0)
1770 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1771 + "Unable to determine the SELinux sid for the job");
1772 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1775 + if (getfilecon(printerfile, &devcon) == -1)
1777 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1778 + "Unable to get the SELinux context of %s",
1780 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1783 + printercon = context_new(devcon);
1784 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1785 + "Printer context %s client context %s",
1786 + context_str(printercon), job->scon);
1787 + context_free(printercon);
1789 + if (avc_context_to_sid(devcon, &psid) != 0)
1791 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1792 + "Unable to determine the SELinux sid for the printer");
1794 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1799 + if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
1802 + * The access check failed, so cancel the job and send an audit message
1804 + if (AuditLog != -1)
1806 + audit_message = NULL;
1807 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s obj=%s canceled"
1808 + " unable to access printer=%s", job->id,
1809 + job->auid, (job->username)?job->username:"?", job->scon, printer->name);
1810 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
1811 + ServerName, NULL, NULL, 0);
1812 + cupsdClearString(&audit_message);
1815 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1821 +#endif /* WITH_LSPP */
1824 * Now start the first file in the job...
1826 diff -up cups-2.2b2/scheduler/job.h.lspp cups-2.2b2/scheduler/job.h
1827 --- cups-2.2b2/scheduler/job.h.lspp 2016-06-24 17:43:35.000000000 +0200
1828 +++ cups-2.2b2/scheduler/job.h 2016-06-27 17:39:48.081973831 +0200
1830 * file is missing or damaged, see the license at "http://www.cups.org/".
1833 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1834 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1837 +#include <selinux/selinux.h>
1838 +#endif /* WITH_LSPP */
1843 @@ -88,6 +95,10 @@ struct cupsd_job_s /**** Job request *
1844 int progress; /* Printing progress */
1845 int num_keywords; /* Number of PPD keywords */
1846 cups_option_t *keywords; /* PPD keywords */
1848 + security_context_t scon; /* Security context of job */
1849 + uid_t auid; /* Audit loginuid for this job */
1850 +#endif /* WITH_LSPP */
1853 typedef struct cupsd_joblog_s /**** Job log message ****/
1854 diff -up cups-2.2b2/scheduler/main.c.lspp cups-2.2b2/scheduler/main.c
1855 --- cups-2.2b2/scheduler/main.c.lspp 2016-06-27 17:39:48.064973966 +0200
1856 +++ cups-2.2b2/scheduler/main.c 2016-06-27 17:39:48.081973831 +0200
1858 # include <sys/param.h>
1859 #endif /* HAVE_SYS_PARAM_H */
1862 +# include <libaudit.h>
1863 +#endif /* WITH_LSPP */
1866 * Local functions...
1867 @@ -122,6 +125,9 @@ main(int argc, /* I - Number of comm
1868 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1869 struct sigaction action; /* Actions for POSIX signals */
1870 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1872 + auditfail_t failmode; /* Action for audit_open failure */
1873 +#endif /* WITH_LSPP */
1875 int use_sysman = 1; /* Use system management functions? */
1877 @@ -505,6 +511,25 @@ main(int argc, /* I - Number of comm
1882 + if ((AuditLog = audit_open()) < 0 )
1884 + if (get_auditfail_action(&failmode) == 0)
1886 + if (failmode == FAIL_LOG)
1888 + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to connect to audit subsystem.");
1891 + else if (failmode == FAIL_TERMINATE)
1893 + fprintf(stderr, "cupsd: unable to start auditing, terminating");
1898 +#endif /* WITH_LSPP */
1901 * Set the timezone info...
1903 @@ -1205,6 +1230,11 @@ main(int argc, /* I - Number of comm
1908 + if (AuditLog != -1)
1909 + audit_close(AuditLog);
1910 +#endif /* WITH_LSPP */
1912 return (!stop_scheduler);
1915 diff -up cups-2.2b2/scheduler/printers.c.lspp cups-2.2b2/scheduler/printers.c
1916 --- cups-2.2b2/scheduler/printers.c.lspp 2016-06-27 17:39:48.013974372 +0200
1917 +++ cups-2.2b2/scheduler/printers.c 2016-06-27 17:39:48.082973823 +0200
1919 * file is missing or damaged, see the license at "http://www.cups.org/".
1922 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1925 * Include necessary headers...
1929 #endif /* __APPLE__ */
1932 +# include <libaudit.h>
1933 +# include <selinux/context.h>
1934 +#endif /* WITH_LSPP */
1937 * Local functions...
1938 @@ -2191,6 +2197,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
1939 ipp_attribute_t *attr; /* Attribute data */
1940 char *name, /* Current user/group name */
1941 *filter; /* Current filter */
1943 + char *audit_message; /* Audit message string */
1944 + char *printerfile; /* Path to a local printer dev */
1945 + char *rangestr; /* Printer's range if its available */
1946 + security_context_t devcon; /* Printer SELinux context */
1947 + context_t printercon; /* context_t for the printer */
1948 +#endif /* WITH_LSPP */
1951 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
1952 @@ -2318,6 +2331,45 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
1953 attr->values[1].string.text = _cupsStrAlloc(Classification ?
1954 Classification : p->job_sheets[1]);
1957 + if (AuditLog != -1)
1959 + audit_message = NULL;
1962 + printerfile = strstr(p->device_uri, "/dev/");
1963 + if (printerfile == NULL && (strncmp(p->device_uri, "file:/", 6) == 0))
1964 + printerfile = p->device_uri + strlen("file:");
1966 + if (printerfile != NULL)
1968 + if (getfilecon(printerfile, &devcon) == -1)
1970 + if(is_selinux_enabled())
1971 + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetPrinterAttrs: Unable to get printer context");
1975 + printercon = context_new(devcon);
1980 + if (printercon && context_range_get(printercon))
1981 + rangestr = strdup(context_range_get(printercon));
1983 + rangestr = strdup("unknown");
1985 + cupsdSetStringf(&audit_message, "printer=%s uri=%s banners=%s,%s range=%s",
1986 + p->name, p->sanitized_device_uri, p->job_sheets[0], p->job_sheets[1], rangestr);
1987 + audit_log_user_message(AuditLog, AUDIT_LABEL_LEVEL_CHANGE, audit_message,
1988 + ServerName, NULL, NULL, 1);
1990 + context_free(printercon);
1992 + cupsdClearString(&audit_message);
1994 +#endif /* WITH_LSPP */