1 diff -up cups-2.3.0/config.h.in.lspp cups-2.3.0/config.h.in
2 --- cups-2.3.0/config.h.in.lspp 2019-08-23 17:19:38.000000000 +0200
3 +++ cups-2.3.0/config.h.in 2019-10-07 12:24:43.058597468 +0200
4 @@ -684,4 +684,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.3.0/config-scripts/cups-lspp.m4.lspp cups-2.3.0/config-scripts/cups-lspp.m4
17 --- cups-2.3.0/config-scripts/cups-lspp.m4.lspp 2019-10-07 12:24:43.058597468 +0200
18 +++ cups-2.3.0/config-scripts/cups-lspp.m4 2019-10-07 12:24:43.058597468 +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.3.0/configure.ac.lspp cups-2.3.0/configure.ac
57 --- cups-2.3.0/configure.ac.lspp 2019-10-07 12:24:43.058597468 +0200
58 +++ cups-2.3.0/configure.ac 2019-10-07 12:39:20.122546282 +0200
59 @@ -34,6 +34,8 @@ sinclude(config-scripts/cups-dnssd.m4)
60 sinclude(config-scripts/cups-startup.m4)
61 sinclude(config-scripts/cups-defaults.m4)
63 +sinclude(config-scripts/cups-lspp.m4)
66 UNINSTALL_LANGUAGES=""
68 diff -up cups-2.3.0/filter/common.c.lspp cups-2.3.0/filter/common.c
69 --- cups-2.3.0/filter/common.c.lspp 2019-08-23 17:19:38.000000000 +0200
70 +++ cups-2.3.0/filter/common.c 2019-10-07 12:24:43.059597461 +0200
72 * Include necessary headers...
79 +#endif /* WITH_LSPP */
84 @@ -293,6 +299,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 @@ -315,6 +333,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 @@ -395,7 +531,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.3.0/filter/pstops.c.lspp cups-2.3.0/filter/pstops.c
240 --- cups-2.3.0/filter/pstops.c.lspp 2019-08-23 17:19:38.000000000 +0200
241 +++ cups-2.3.0/filter/pstops.c 2019-10-07 12:24:43.059597461 +0200
242 @@ -3170,6 +3170,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 @@ -3192,6 +3204,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 @@ -3270,7 +3400,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.3.0/Makedefs.in.lspp cups-2.3.0/Makedefs.in
398 --- cups-2.3.0/Makedefs.in.lspp 2019-10-07 12:24:43.059597461 +0200
399 +++ cups-2.3.0/Makedefs.in 2019-10-07 12:37:19.200565805 +0200
400 @@ -174,7 +174,7 @@ IPPFIND_MAN = @IPPFIND_MAN@
402 LINKCUPS = @LINKCUPS@
403 LINKCUPSSTATIC = ../cups/$(LIBCUPSSTATIC) $(LIBS)
404 -LIBS = $(LIBGSSAPI) $(DNSSDLIBS) $(SSLLIBS) $(LIBZ) $(COMMONLIBS)
405 +LIBS = $(LIBGSSAPI) $(DNSSDLIBS) $(SSLLIBS) $(LIBZ) $(COMMONLIBS) @LIBAUDIT@ @LIBSELINUX@
406 ONDEMANDFLAGS = @ONDEMANDFLAGS@
407 ONDEMANDLIBS = @ONDEMANDLIBS@
409 diff -up cups-2.3.0/scheduler/client.c.lspp cups-2.3.0/scheduler/client.c
410 --- cups-2.3.0/scheduler/client.c.lspp 2019-08-23 17:19:38.000000000 +0200
411 +++ cups-2.3.0/scheduler/client.c 2019-10-07 12:33:10.459693580 +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 @@ -265,6 +273,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 @@ -558,6 +619,13 @@ cupsdReadClient(cupsd_client_t *con) /*
494 struct stat filestats; /* File information */
495 mime_type_t *type; /* MIME type of file */
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 @@ -1679,6 +1747,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 @@ -3174,6 +3309,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.3.0/scheduler/client.h.lspp cups-2.3.0/scheduler/client.h
632 --- cups-2.3.0/scheduler/client.h.lspp 2019-08-23 17:19:38.000000000 +0200
633 +++ cups-2.3.0/scheduler/client.h 2019-10-07 12:24:43.113597079 +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 @@ -63,6 +70,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 @@ -136,6 +147,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.3.0/scheduler/conf.c.lspp cups-2.3.0/scheduler/conf.c
670 --- cups-2.3.0/scheduler/conf.c.lspp 2019-10-07 12:24:43.049597531 +0200
671 +++ cups-2.3.0/scheduler/conf.c 2019-10-07 12:24:43.113597079 +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 @@ -544,6 +551,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 @@ -864,6 +874,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 @@ -1275,7 +1304,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 @@ -3830,6 +3871,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.3.0/scheduler/conf.h.lspp cups-2.3.0/scheduler/conf.h
769 --- cups-2.3.0/scheduler/conf.h.lspp 2019-08-23 17:19:38.000000000 +0200
770 +++ cups-2.3.0/scheduler/conf.h 2019-10-07 12:24:43.113597079 +0200
771 @@ -243,6 +243,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 @@ -261,6 +268,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.3.0/scheduler/cupsd.h.lspp cups-2.3.0/scheduler/cupsd.h
796 --- cups-2.3.0/scheduler/cupsd.h.lspp 2019-08-23 17:19:38.000000000 +0200
797 +++ cups-2.3.0/scheduler/cupsd.h 2019-10-07 12:31:38.458480578 +0200
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 diff -up cups-2.3.0/scheduler/ipp.c.lspp cups-2.3.0/scheduler/ipp.c
823 --- cups-2.3.0/scheduler/ipp.c.lspp 2019-10-07 12:24:43.016597764 +0200
824 +++ cups-2.3.0/scheduler/ipp.c 2019-10-07 12:31:01.243798920 +0200
829 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
830 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
833 * Include necessary headers...
835 @@ -27,6 +30,14 @@ extern int mbr_group_name_to_uuid(const
836 extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
837 #endif /* __APPLE__ */
840 +#include <libaudit.h>
841 +#include <selinux/selinux.h>
842 +#include <selinux/context.h>
843 +#include <selinux/avc.h>
844 +#include <selinux/flask.h>
845 +#include <selinux/av_permissions.h>
846 +#endif /* WITH_LSPP */
850 @@ -51,6 +62,9 @@ static void cancel_all_jobs(cupsd_client
851 static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
852 static void cancel_subscription(cupsd_client_t *con, int id);
853 static int check_rss_recipient(const char *recipient);
855 +static int check_context(cupsd_client_t *con, cupsd_job_t *job);
856 +#endif /* WITH_LSPP */
857 static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
858 static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
859 static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
860 @@ -1240,6 +1254,21 @@ add_job(cupsd_client_t *con, /* I - Cl
865 + char *audit_message; /* Audit message string */
866 + char *printerfile; /* device file pointed to by the printer */
867 + char *userheader = NULL; /* User supplied job-sheets[0] */
868 + char *userfooter = NULL; /* User supplied job-sheets[1] */
869 + int override = 0; /* Was a banner overrode on a job */
870 + security_id_t clisid; /* SELinux SID for the client */
871 + security_id_t psid; /* SELinux SID for the printer */
872 + context_t printercon; /* Printer's context string */
873 + struct stat printerstat; /* Printer's stat buffer */
874 + security_context_t devcon; /* Printer's SELinux context */
875 + struct avc_entry_ref avcref; /* Pointer to the access vector cache */
876 + security_class_t tclass; /* Object class for the SELinux check */
877 + access_vector_t avr; /* Access method being requested */
878 +#endif /* WITH_LSPP */
881 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
882 @@ -1568,6 +1597,106 @@ add_job(cupsd_client_t *con, /* I - Cl
884 attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
887 + if (is_lspp_config())
889 + if (!con->scon || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
891 + cupsdLogMessage(CUPSD_LOG_ERROR, "add_job: missing classification for connection \'%s\'!", printer->name);
892 + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Missing required security attributes."));
897 + * Perform an access check so that if the user gets feedback at enqueue time
900 + printerfile = strstr(printer->device_uri, "/dev/");
901 + if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
902 + printerfile = printer->device_uri + strlen("file:");
904 + if (printerfile != NULL)
906 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: Attempting an access check on printer device %s",
909 + if (lstat(printerfile, &printerstat) < 0)
911 + if (errno != ENOENT)
913 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to stat the printer"));
917 + * The printer does not exist, so for now assume it's a FileDevice
919 + tclass = SECCLASS_FILE;
922 + else if (S_ISCHR(printerstat.st_mode))
924 + tclass = SECCLASS_CHR_FILE;
925 + avr = CHR_FILE__WRITE;
927 + else if (S_ISREG(printerstat.st_mode))
929 + tclass = SECCLASS_FILE;
934 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Printer is not a character device or regular file"));
937 + static int avc_initialized = 0;
938 + if (!avc_initialized++)
939 + avc_init("cupsd_enqueue_", NULL, NULL, NULL, NULL);
940 + avc_entry_ref_init(&avcref);
941 + if (avc_context_to_sid(con->scon, &clisid) != 0)
943 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the client"));
946 + if (getfilecon(printerfile, &devcon) == -1)
948 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux context of the printer"));
951 + printercon = context_new(devcon);
952 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: printer context %s client context %s",
953 + context_str(printercon), con->scon);
954 + context_free(printercon);
956 + if (avc_context_to_sid(devcon, &psid) != 0)
958 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the printer"));
963 + if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
966 + * The access check failed, so cancel the job and send an audit message
968 + if (AuditLog != -1)
970 + audit_message = NULL;
971 + cupsdSetStringf(&audit_message, "job=? auid=%u acct=%s obj=%s refused"
972 + " unable to access printer=%s", con->auid,
973 + con->username, con->scon, printer->name);
974 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
975 + ServerName, NULL, NULL, 0);
976 + cupsdClearString(&audit_message);
979 + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("SELinux prohibits access to the printer"));
984 +#endif /* WITH_LSPP */
986 if ((job = cupsdAddJob(priority, printer->name)) == NULL)
988 send_ipp_status(con, IPP_INTERNAL_ERROR,
989 @@ -1576,6 +1705,32 @@ add_job(cupsd_client_t *con, /* I - Cl
994 + if (is_lspp_config())
997 + * duplicate the security context and auid of the connection into the job structure
999 + job->scon = strdup(con->scon);
1000 + job->auid = con->auid;
1003 + * add the security context to the request so that on a restart the security
1004 + * attributes will be able to be restored
1006 + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "security-context",
1012 + * Fill in the security context of the job as unlabeled
1014 + cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: setting context of job to %s", UNKNOWN_SL);
1015 + cupsdSetString(&job->scon, UNKNOWN_SL);
1017 +#endif /* WITH_LSPP */
1019 job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
1020 job->attrs = con->request;
1022 @@ -1763,6 +1918,29 @@ add_job(cupsd_client_t *con, /* I - Cl
1023 ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
1024 ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
1030 + * The option was present, so capture the user supplied strings
1032 + userheader = strdup(attr->values[0].string.text);
1034 + if (attr->num_values > 1)
1035 + userfooter = strdup(attr->values[1].string.text);
1037 + if (Classification != NULL && (strcmp(userheader, Classification) == 0)
1038 + && userfooter &&(strcmp(userfooter, Classification) == 0))
1041 + * Since both values are Classification, the user is not trying to Override
1044 + if (userfooter) free(userfooter);
1045 + userheader = userfooter = NULL;
1048 +#endif /* WITH_LSPP */
1050 job->job_sheets = attr;
1052 @@ -1793,6 +1971,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1053 "job-sheets=\"%s,none\", "
1054 "job-originating-user-name=\"%s\"",
1055 Classification, job->username);
1058 +#endif /* WITH_LSPP */
1060 else if (attr->num_values == 2 &&
1061 strcmp(attr->values[0].string.text,
1062 @@ -1811,6 +1992,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1063 "job-originating-user-name=\"%s\"",
1064 attr->values[0].string.text,
1065 attr->values[1].string.text, job->username);
1068 +#endif /* WITH_LSPP */
1070 else if (strcmp(attr->values[0].string.text, Classification) &&
1071 strcmp(attr->values[0].string.text, "none") &&
1072 @@ -1831,6 +2015,9 @@ add_job(cupsd_client_t *con, /* I - Cl
1073 "job-originating-user-name=\"%s\"",
1074 attr->values[0].string.text,
1075 attr->values[1].string.text, job->username);
1078 +#endif /* WITH_LSPP */
1081 else if (strcmp(attr->values[0].string.text, Classification) &&
1082 @@ -1871,8 +2058,52 @@ add_job(cupsd_client_t *con, /* I - Cl
1083 "job-sheets=\"%s\", "
1084 "job-originating-user-name=\"%s\"",
1085 Classification, job->username);
1088 +#endif /* WITH_LSPP */
1091 + if (is_lspp_config() && AuditLog != -1)
1093 + audit_message = NULL;
1095 + if (userheader || userfooter)
1100 + * The user overrode the banner, so audit it
1102 + cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
1103 + " using banners=%s,%s", job->id, userheader,
1104 + userfooter, attr->values[0].string.text,
1105 + (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
1106 + audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
1107 + ServerName, NULL, NULL, 1);
1112 + * The user tried to override the banner, audit the failure
1114 + cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
1115 + " ignored banners=%s,%s", job->id, userheader,
1116 + userfooter, attr->values[0].string.text,
1117 + (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
1118 + audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
1119 + ServerName, NULL, NULL, 0);
1121 + cupsdClearString(&audit_message);
1129 +#endif /* WITH_LSPP */
1134 * See if we need to add the starting sheet...
1135 @@ -3648,6 +3879,128 @@ check_rss_recipient(
1141 + * 'check_context()' - Check SELinux security context of a user and job
1144 +static int /* O - 1 if OK, 0 if not, -1 on error */
1145 +check_context(cupsd_client_t *con, /* I - Client connection */
1146 + cupsd_job_t *job) /* I - Job */
1148 + int enforcing; /* is SELinux in enforcing mode */
1149 + char filename[1024]; /* Filename of the spool file */
1150 + security_id_t clisid; /* SELinux SID of the client */
1151 + security_id_t jobsid; /* SELinux SID of the job */
1152 + security_id_t filesid; /* SELinux SID of the spool file */
1153 + struct avc_entry_ref avcref; /* AVC entry cache pointer */
1154 + security_class_t tclass; /* SELinux security class */
1155 + access_vector_t avr; /* SELinux access being queried */
1156 + security_context_t spoolfilecon; /* SELinux context of the spool file */
1160 + * Validate the input to be sure there are contexts to work with...
1163 + if (con->scon == NULL || job->scon == NULL
1164 + || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0
1165 + || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
1168 + if ((enforcing = security_getenforce()) == -1)
1170 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1171 + "Error while determining SELinux enforcement");
1174 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1175 + "check_context: client context %s job context %s",
1176 + con->scon, job->scon);
1180 + * Initialize the avc engine...
1183 + static int avc_initialized = 0;
1184 + if (! avc_initialized++)
1186 + if (avc_init("cupsd", NULL, NULL, NULL, NULL) < 0)
1188 + cupsdLogJob(job, CUPSD_LOG_ERROR, "check_context: unable avc_init");
1192 + if (avc_context_to_sid(con->scon, &clisid) != 0)
1194 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1195 + "check_context: unable to convert %s to SELinux sid",
1199 + if (avc_context_to_sid(job->scon, &jobsid) != 0)
1201 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1202 + "check_context: unable to convert %s to SELinux sid",
1206 + avc_entry_ref_init(&avcref);
1207 + tclass = SECCLASS_FILE;
1211 + * Perform the check with the client as the subject, first with the job as the object
1212 + * if that fails then with the spool file as the object...
1215 + if (avc_has_perm_noaudit(clisid, jobsid, tclass, avr, &avcref, NULL) != 0)
1217 + cupsdLogJob(job, CUPSD_LOG_INFO,
1218 + "check_context: SELinux denied access "
1219 + "based on the client context");
1221 + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
1222 + if (getfilecon(filename, &spoolfilecon) == -1)
1224 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1225 + "check_context: Unable to get spoolfile context");
1228 + if (avc_context_to_sid(spoolfilecon, &filesid) != 0)
1230 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1231 + "check_context: Unable to determine the "
1232 + "SELinux sid for the spool file");
1233 + freecon(spoolfilecon);
1236 + freecon(spoolfilecon);
1237 + if (avc_has_perm_noaudit(clisid, filesid, tclass, avr, &avcref, NULL) != 0)
1239 + cupsdLogJob(job, CUPSD_LOG_INFO,
1240 + "check_context: SELinux denied access to the spool file");
1243 + cupsdLogJob(job, CUPSD_LOG_INFO,
1244 + "check_context: SELinux allowed access to the spool file");
1248 + if (enforcing == 0)
1249 + cupsdLogJob(job, CUPSD_LOG_INFO,
1250 + "check_context: allowing operation due to permissive mode");
1252 + cupsdLogJob(job, CUPSD_LOG_INFO,
1253 + "check_context: SELinux allowed access based on the "
1254 + "client context");
1258 +#endif /* WITH_LSPP */
1262 * 'check_quotas()' - Check quotas for a printer and user.
1264 @@ -4103,6 +4456,15 @@ copy_banner(cupsd_client_t *con, /* I -
1265 char attrname[255], /* Name of attribute */
1266 *s; /* Pointer into name */
1267 ipp_attribute_t *attr; /* Attribute */
1269 + const char *mls_label; /* SL of print job */
1270 + char *jobrange; /* SELinux sensitivity range */
1271 + char *jobclearance; /* SELinux low end clearance */
1272 + context_t jobcon; /* SELinux context of the job */
1273 + context_t tmpcon; /* Temp context to set the level */
1274 + security_context_t spoolcon; /* Context of the file in the spool */
1275 +#endif /* WITH_LSPP */
1279 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1280 @@ -4138,6 +4500,85 @@ copy_banner(cupsd_client_t *con, /* I -
1282 fchmod(cupsFileNumber(out), 0640);
1283 fchown(cupsFileNumber(out), RunUser, Group);
1285 + if (job->scon != NULL &&
1286 + strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1288 + if (getfilecon(filename, &spoolcon) == -1)
1290 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1291 + "Unable to get the context of the banner file %s - %s",
1292 + filename, strerror(errno));
1293 + job->num_files --;
1296 + tmpcon = context_new(spoolcon);
1297 + jobcon = context_new(job->scon);
1298 + freecon(spoolcon);
1299 + if (!tmpcon || !jobcon)
1302 + context_free(tmpcon);
1304 + context_free(jobcon);
1305 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1306 + "copy_banner: Unable to get the SELinux contexts");
1307 + job->num_files --;
1310 + jobrange = (char *) context_range_get(jobcon);
1313 + jobrange = strdup(jobrange);
1314 + if ((jobclearance = strtok(jobrange, "-")) != NULL)
1316 + if (context_range_set(tmpcon, jobclearance) == -1)
1318 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1319 + "copy_banner: Unable to set the "
1320 + "level of the context for file %s - %s",
1321 + filename, strerror(errno));
1323 + context_free(jobcon);
1324 + context_free(tmpcon);
1325 + job->num_files --;
1331 + if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1333 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1334 + "copy_banner: Unable to set the "
1335 + "level of the context for file %s - %s",
1336 + filename, strerror(errno));
1338 + context_free(jobcon);
1339 + context_free(tmpcon);
1340 + job->num_files --;
1346 + if (setfilecon(filename, context_str(tmpcon)) == -1)
1348 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1349 + "copy_banner: Unable to set the "
1350 + "context of the banner file %s - %s",
1351 + filename, strerror(errno));
1352 + context_free(jobcon);
1353 + context_free(tmpcon);
1354 + job->num_files --;
1357 + cupsdLogJob(job, CUPSD_LOG_DEBUG2, "copy_banner: %s set to %s",
1358 + filename, context_str(tmpcon));
1359 + context_free(jobcon);
1360 + context_free(tmpcon);
1362 +#endif /* WITH_LSPP */
1365 * Try the localized banner file under the subdirectory...
1366 @@ -4232,6 +4673,24 @@ copy_banner(cupsd_client_t *con, /* I -
1371 + if (strcmp(s, "mls-label") == 0)
1373 + if (job->scon != NULL && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1375 + jobcon = context_new(job->scon);
1376 + if (_cups_strcasecmp(name, MLS_CONFIG) == 0)
1377 + mls_label = context_range_get(jobcon);
1378 + else if (_cups_strcasecmp(name, TE_CONFIG) == 0)
1379 + mls_label = context_type_get(jobcon);
1380 + else // default to using the whole context string
1381 + mls_label = context_str(jobcon);
1382 + cupsFilePuts(out, mls_label);
1383 + context_free(jobcon);
1387 +#endif /* WITH_LSPP */
1388 if (!strcmp(s, "printer-name"))
1390 cupsFilePuts(out, job->dest);
1391 @@ -6439,6 +6898,22 @@ get_job_attrs(cupsd_client_t *con, /* I
1393 exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
1398 + * Check SELinux...
1400 + if (is_lspp_config() && check_context(con, job) != 1)
1403 + * Unfortunately we have to lie to the user...
1405 + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
1408 +#endif /* WITH_LSPP */
1412 * Copy attributes...
1414 @@ -6836,6 +7311,11 @@ get_jobs(cupsd_client_t *con, /* I - C
1415 if (username[0] && _cups_strcasecmp(username, job->username))
1419 + if (is_lspp_config() && check_context(con, job) != 1)
1421 +#endif /* WITH_LSPP */
1424 ippAddSeparator(con->response);
1426 @@ -11445,6 +11925,11 @@ validate_user(cupsd_job_t *job, /* I
1428 strlcpy(username, get_username(con), userlen);
1431 + if (is_lspp_config() && check_context(con, job) != 1)
1433 +#endif /* WITH_LSPP */
1436 * Check the username against the owner...
1438 diff -up cups-2.3.0/scheduler/job.c.lspp cups-2.3.0/scheduler/job.c
1439 --- cups-2.3.0/scheduler/job.c.lspp 2019-10-07 12:24:43.024597707 +0200
1440 +++ cups-2.3.0/scheduler/job.c 2019-10-07 12:30:13.092210820 +0200
1445 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1446 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1449 * Include necessary headers...
1452 # endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
1453 #endif /* __APPLE__ */
1456 +#include <libaudit.h>
1457 +#include <selinux/selinux.h>
1458 +#include <selinux/context.h>
1459 +#include <selinux/avc.h>
1460 +#include <selinux/flask.h>
1461 +#include <selinux/av_permissions.h>
1462 +#endif /* WITH_LSPP */
1465 * Design Notes for Job Management
1466 @@ -544,6 +555,14 @@ cupsdContinueJob(cupsd_job_t *job) /* I
1467 /* PRINTER_STATE_REASONS env var */
1469 /* RIP_MAX_CACHE env variable */
1471 + char *audit_message = NULL; /* Audit message string */
1472 + context_t jobcon; /* SELinux context of the job */
1473 + char *label_template = NULL; /* SL to put in classification
1475 + const char *mls_label = NULL; /* SL to put in classification
1477 +#endif /* WITH_LSPP */
1480 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1481 @@ -1080,6 +1099,67 @@ cupsdContinueJob(cupsd_job_t *job) /* I
1482 if (final_content_type[0])
1483 envp[envc ++] = final_content_type;
1486 + if (is_lspp_config())
1488 + if (!job->scon || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
1490 + if (AuditLog != -1)
1492 + audit_message = NULL;
1493 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s",
1494 + job->id, job->auid, job->username, job->printer->name, title);
1495 + audit_log_user_message(AuditLog, AUDIT_USER_UNLABELED_EXPORT, audit_message,
1496 + ServerName, NULL, NULL, 1);
1497 + cupsdClearString(&audit_message);
1502 + jobcon = context_new(job->scon);
1504 + if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME)) == NULL)
1505 + label_template = strdup(Classification);
1506 + else if (attr->num_values > 1 &&
1507 + strcmp(attr->values[1].string.text, "none") != 0)
1508 + label_template = strdup(attr->values[1].string.text);
1510 + label_template = strdup(attr->values[0].string.text);
1512 + if (_cups_strcasecmp(label_template, MLS_CONFIG) == 0)
1513 + mls_label = context_range_get(jobcon);
1514 + else if (_cups_strcasecmp(label_template, TE_CONFIG) == 0)
1515 + mls_label = context_type_get(jobcon);
1516 + else if (_cups_strcasecmp(label_template, SELINUX_CONFIG) == 0)
1517 + mls_label = context_str(jobcon);
1519 + mls_label = label_template;
1521 + if (mls_label && (PerPageLabels || banner_page))
1523 + snprintf(classification, sizeof(classification), "CLASSIFICATION=LSPP:%s", mls_label);
1524 + envp[envc ++] = classification;
1527 + if ((AuditLog != -1) && !banner_page)
1529 + audit_message = NULL;
1530 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s"
1531 + " obj=%s label=%s", job->id, job->auid, job->username,
1532 + job->printer->name, title, job->scon, mls_label?mls_label:"none");
1533 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
1534 + ServerName, NULL, NULL, 1);
1535 + cupsdClearString(&audit_message);
1537 + context_free(jobcon);
1538 + free(label_template);
1543 + * Fall through to the non-LSPP behavior
1545 +#endif /* WITH_LSPP */
1546 if (Classification && !banner_page)
1548 if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1549 @@ -1858,6 +1938,22 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J
1550 ippSetString(job->attrs, &job->reasons, 0, "none");
1554 + if ((attr = ippFindAttribute(job->attrs, "security-context", IPP_TAG_NAME)) != NULL)
1555 + cupsdSetString(&job->scon, attr->values[0].string.text);
1556 + else if (is_lspp_config())
1559 + * There was no security context so delete the job
1561 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1562 + "Missing or bad security-context attribute "
1563 + "in control file \"%s\"!",
1567 +#endif /* WITH_LSPP */
1569 job->impressions = ippFindAttribute(job->attrs, "job-impressions-completed", IPP_TAG_INTEGER);
1570 job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER);
1571 job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
1572 @@ -2273,6 +2369,14 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
1574 char filename[1024]; /* Job control filename */
1575 cups_file_t *fp; /* Job file */
1577 + security_context_t spoolcon; /* context of the job control file */
1578 + context_t jobcon; /* contex_t container for job->scon */
1579 + context_t tmpcon; /* Temp context to swap the level */
1580 + char *jobclearance; /* SELinux low end clearance */
1581 + const char *jobrange; /* SELinux sensitivity range */
1582 + char *jobrange_copy; /* SELinux sensitivity range */
1583 +#endif /* WITH_LSPP */
1586 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
1587 @@ -2295,6 +2399,78 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
1589 fchown(cupsFileNumber(fp), RunUser, Group);
1592 + if (job->scon && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1594 + if (getfilecon(filename, &spoolcon) == -1)
1596 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1597 + "Unable to get context of job control file \"%s\" - %s.",
1598 + filename, strerror(errno));
1601 + jobcon = context_new(job->scon);
1602 + tmpcon = context_new(spoolcon);
1603 + freecon(spoolcon);
1604 + if (!jobcon || !tmpcon)
1607 + context_free(jobcon);
1609 + context_free(tmpcon);
1610 + cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to get SELinux contexts");
1613 + jobrange = context_range_get(jobcon);
1616 + jobrange_copy = strdup(jobrange);
1617 + if ((jobclearance = strtok(jobrange_copy, "-")) != NULL)
1619 + if (context_range_set(tmpcon, jobclearance) == -1)
1621 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1622 + "Unable to set the range for "
1623 + "job control file \"%s\" - %s.",
1624 + filename, strerror(errno));
1625 + free(jobrange_copy);
1626 + context_free(tmpcon);
1627 + context_free(jobcon);
1633 + if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1635 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1636 + "Unable to set the range for "
1637 + "job control file \"%s\" - %s.",
1638 + filename, strerror(errno));
1639 + free(jobrange_copy);
1640 + context_free(tmpcon);
1641 + context_free(jobcon);
1645 + free(jobrange_copy);
1647 + if (setfilecon(filename, context_str(tmpcon)) == -1)
1649 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1650 + "Unable to set context of job control file \"%s\" - %s.",
1651 + filename, strerror(errno));
1652 + context_free(tmpcon);
1653 + context_free(jobcon);
1656 + cupsdLogJob(job, CUPSD_LOG_DEBUG2, "New spool file context=%s",
1657 + context_str(tmpcon));
1658 + context_free(tmpcon);
1659 + context_free(jobcon);
1661 +#endif /* WITH_LSPP */
1663 job->attrs->state = IPP_IDLE;
1665 if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
1666 @@ -3995,6 +4171,19 @@ get_options(cupsd_job_t *job, /* I - Jo
1672 + * In LSPP mode refuse to honor the page-label
1674 + if (is_lspp_config() &&
1675 + !strcmp(attr->name, "page-label"))
1677 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1678 + "Ignoring page-label option due to LSPP mode");
1681 +#endif /* WITH_LSPP */
1684 * Otherwise add them to the list...
1686 @@ -4805,6 +4994,18 @@ start_job(cupsd_job_t *job, /* I -
1687 cupsd_printer_t *printer) /* I - Printer to print job */
1689 const char *filename; /* Support filename */
1691 + char *audit_message = NULL; /* Audit message string */
1692 + char *printerfile = NULL; /* Device file pointed to by the printer */
1693 + security_id_t clisid; /* SELinux SID for the client */
1694 + security_id_t psid; /* SELinux SID for the printer */
1695 + context_t printercon; /* Printer's context string */
1696 + struct stat printerstat; /* Printer's stat buffer */
1697 + security_context_t devcon; /* Printer's SELinux context */
1698 + struct avc_entry_ref avcref; /* Pointer to the access vector cache */
1699 + security_class_t tclass; /* Object class for the SELinux check */
1700 + access_vector_t avr; /* Access method being requested */
1701 +#endif /* WITH_LSPP */
1702 ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
1705 @@ -4993,6 +5194,113 @@ start_job(cupsd_job_t *job, /* I -
1706 fcntl(job->side_pipes[1], F_SETFD,
1707 fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
1710 + if (is_lspp_config())
1713 + * Perform an access check before printing, but only if the printer starts with /dev/
1715 + printerfile = strstr(printer->device_uri, "/dev/");
1716 + if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
1717 + printerfile = printer->device_uri + strlen("file:");
1719 + if (printerfile != NULL)
1721 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1722 + "Attempting to check access on printer device %s",
1724 + if (lstat(printerfile, &printerstat) < 0)
1726 + if (errno != ENOENT)
1728 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1729 + "Unable to stat the printer");
1730 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1734 + * The printer does not exist, so for now assume it's a FileDevice
1736 + tclass = SECCLASS_FILE;
1737 + avr = FILE__WRITE;
1739 + else if (S_ISCHR(printerstat.st_mode))
1741 + tclass = SECCLASS_CHR_FILE;
1742 + avr = CHR_FILE__WRITE;
1744 + else if (S_ISREG(printerstat.st_mode))
1746 + tclass = SECCLASS_FILE;
1747 + avr = FILE__WRITE;
1751 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1752 + "StartJob: Printer is not a character device or "
1754 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1757 + static int avc_initialized = 0;
1758 + if (!avc_initialized++)
1759 + avc_init("cupsd_dequeue_", NULL, NULL, NULL, NULL);
1760 + avc_entry_ref_init(&avcref);
1761 + if (avc_context_to_sid(job->scon, &clisid) != 0)
1763 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1764 + "Unable to determine the SELinux sid for the job");
1765 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1768 + if (getfilecon(printerfile, &devcon) == -1)
1770 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1771 + "Unable to get the SELinux context of %s",
1773 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1776 + printercon = context_new(devcon);
1777 + cupsdLogJob(job, CUPSD_LOG_DEBUG,
1778 + "Printer context %s client context %s",
1779 + context_str(printercon), job->scon);
1780 + context_free(printercon);
1782 + if (avc_context_to_sid(devcon, &psid) != 0)
1784 + cupsdLogJob(job, CUPSD_LOG_ERROR,
1785 + "Unable to determine the SELinux sid for the printer");
1787 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1792 + if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
1795 + * The access check failed, so cancel the job and send an audit message
1797 + if (AuditLog != -1)
1799 + audit_message = NULL;
1800 + cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s obj=%s canceled"
1801 + " unable to access printer=%s", job->id,
1802 + job->auid, (job->username)?job->username:"?", job->scon, printer->name);
1803 + audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
1804 + ServerName, NULL, NULL, 0);
1805 + cupsdClearString(&audit_message);
1808 + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1814 +#endif /* WITH_LSPP */
1817 * Now start the first file in the job...
1819 diff -up cups-2.3.0/scheduler/job.h.lspp cups-2.3.0/scheduler/job.h
1820 --- cups-2.3.0/scheduler/job.h.lspp 2019-08-23 17:19:38.000000000 +0200
1821 +++ cups-2.3.0/scheduler/job.h 2019-10-07 12:29:54.364371023 +0200
1823 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
1826 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1827 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1830 +#include <selinux/selinux.h>
1831 +#endif /* WITH_LSPP */
1836 @@ -84,6 +91,10 @@ struct cupsd_job_s /**** Job request *
1837 int progress; /* Printing progress */
1838 int num_keywords; /* Number of PPD keywords */
1839 cups_option_t *keywords; /* PPD keywords */
1841 + security_context_t scon; /* Security context of job */
1842 + uid_t auid; /* Audit loginuid for this job */
1843 +#endif /* WITH_LSPP */
1846 typedef struct cupsd_joblog_s /**** Job log message ****/
1847 diff -up cups-2.3.0/scheduler/main.c.lspp cups-2.3.0/scheduler/main.c
1848 --- cups-2.3.0/scheduler/main.c.lspp 2019-10-07 12:24:43.037597616 +0200
1849 +++ cups-2.3.0/scheduler/main.c 2019-10-07 12:24:43.119597037 +0200
1851 # include <sys/param.h>
1852 #endif /* HAVE_SYS_PARAM_H */
1855 +# include <libaudit.h>
1856 +#endif /* WITH_LSPP */
1859 * Local functions...
1860 @@ -123,6 +126,9 @@ main(int argc, /* I - Number of comm
1861 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1862 struct sigaction action; /* Actions for POSIX signals */
1863 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1865 + auditfail_t failmode; /* Action for audit_open failure */
1866 +#endif /* WITH_LSPP */
1868 int use_sysman = 1; /* Use system management functions? */
1870 @@ -495,6 +501,25 @@ main(int argc, /* I - Number of comm
1875 + if ((AuditLog = audit_open()) < 0 )
1877 + if (get_auditfail_action(&failmode) == 0)
1879 + if (failmode == FAIL_LOG)
1881 + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to connect to audit subsystem.");
1884 + else if (failmode == FAIL_TERMINATE)
1886 + fprintf(stderr, "cupsd: unable to start auditing, terminating");
1891 +#endif /* WITH_LSPP */
1894 * Let the system know we are busy while we bring up cupsd...
1896 @@ -1201,6 +1226,11 @@ main(int argc, /* I - Number of comm
1901 + if (AuditLog != -1)
1902 + audit_close(AuditLog);
1903 +#endif /* WITH_LSPP */
1905 return (!stop_scheduler);
1908 diff -up cups-2.3.0/scheduler/printers.c.lspp cups-2.3.0/scheduler/printers.c
1909 --- cups-2.3.0/scheduler/printers.c.lspp 2019-08-23 17:19:38.000000000 +0200
1910 +++ cups-2.3.0/scheduler/printers.c 2019-10-07 12:29:17.956658129 +0200
1915 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1918 * Include necessary headers...
1922 #endif /* __APPLE__ */
1925 +# include <libaudit.h>
1926 +# include <selinux/context.h>
1927 +#endif /* WITH_LSPP */
1930 * Local functions...
1931 @@ -2252,6 +2258,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
1932 ipp_attribute_t *attr; /* Attribute data */
1933 char *name, /* Current user/group name */
1934 *filter; /* Current filter */
1936 + char *audit_message; /* Audit message string */
1937 + char *printerfile; /* Path to a local printer dev */
1938 + char *rangestr; /* Printer's range if its available */
1939 + security_context_t devcon; /* Printer SELinux context */
1940 + context_t printercon; /* context_t for the printer */
1941 +#endif /* WITH_LSPP */
1945 @@ -2378,6 +2391,45 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
1946 attr->values[1].string.text = _cupsStrAlloc(Classification ?
1947 Classification : p->job_sheets[1]);
1950 + if (AuditLog != -1)
1952 + audit_message = NULL;
1955 + printerfile = strstr(p->device_uri, "/dev/");
1956 + if (printerfile == NULL && (strncmp(p->device_uri, "file:/", 6) == 0))
1957 + printerfile = p->device_uri + strlen("file:");
1959 + if (printerfile != NULL)
1961 + if (getfilecon(printerfile, &devcon) == -1)
1963 + if(is_selinux_enabled())
1964 + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetPrinterAttrs: Unable to get printer context");
1968 + printercon = context_new(devcon);
1973 + if (printercon && context_range_get(printercon))
1974 + rangestr = strdup(context_range_get(printercon));
1976 + rangestr = strdup("unknown");
1978 + cupsdSetStringf(&audit_message, "printer=%s uri=%s banners=%s,%s range=%s",
1979 + p->name, p->sanitized_device_uri, p->job_sheets[0], p->job_sheets[1], rangestr);
1980 + audit_log_user_message(AuditLog, AUDIT_LABEL_LEVEL_CHANGE, audit_message,
1981 + ServerName, NULL, NULL, 1);
1983 + context_free(printercon);
1985 + cupsdClearString(&audit_message);
1987 +#endif /* WITH_LSPP */