]> git.pld-linux.org Git - packages/cups.git/blob - cups-lspp.patch
Release 4 (by relup.sh)
[packages/cups.git] / cups-lspp.patch
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 */
7  
8 +/*
9 + * Are we trying to meet LSPP requirements?
10 + */
11 +
12 +#undef WITH_LSPP
13 +
14 +
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
19 @@ -0,0 +1,36 @@
20 +dnl
21 +dnl   LSPP code for the Common UNIX Printing System (CUPS).
22 +dnl
23 +dnl   Copyright 2005-2006 by Hewlett-Packard Development Company, L.P.
24 +dnl
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.
28 +dnl
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.
33 +dnl
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
37 +dnl
38 +
39 +dnl Are we trying to meet LSPP requirements
40 +AC_ARG_ENABLE(lspp, [  --enable-lspp           turn on auditing and label support, default=no])
41 +
42 +if test x"$enable_lspp" != xno; then
43 +    case "$uname" in
44 +        Linux)
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)
50 +            ;;
51 +        *)
52 +            # All others
53 +            ;;
54 +    esac
55 +fi
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)
62  
63 +sinclude(config-scripts/cups-lspp.m4)
64 +
65  INSTALL_LANGUAGES=""
66  UNINSTALL_LANGUAGES=""
67  LANGFILES=""
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
71 @@ -11,6 +11,12 @@
72   * Include necessary headers...
73   */
74  
75 +#include "config.h"
76 +#ifdef WITH_LSPP
77 +#define _GNU_SOURCE
78 +#include <string.h>
79 +#endif /* WITH_LSPP */
80 +
81  #include "common.h"
82  #include <locale.h>
83  
84 @@ -293,6 +299,18 @@ WriteLabelProlog(const char *label,        /* I
85  {
86    const char   *classification;        /* CLASSIFICATION environment variable */
87    const char   *ptr;                   /* Temporary string pointer */
88 +#ifdef WITH_LSPP
89 +  int           i,                      /* counter */
90 +                n,                      /* 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 */
100  
101  
102   /*
103 @@ -315,6 +333,124 @@ WriteLabelProlog(const char *label,       /* I
104      return;
105    }
106  
107 +#ifdef WITH_LSPP
108 +  if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
109 +  {
110 +   /*
111 +    * Based on the 12pt fixed width font below determine the max_width
112 +    */
113 +    max_width = width / 8;
114 +    longest_line = 0;
115 +    longest = 0;
116 +    classification += 5; // Skip the "LSPP:"
117 +    label_len = strlen(classification);
118 +
119 +    if (label_len > max_width)
120 +    {
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])
126 +      {
127 +        if ((label_index + line_len) > label_len)
128 +          break;
129 +        switch (classification[label_index + line_len + i])
130 +        {
131 +          case ':':
132 +          case ',':
133 +          case '-':
134 +            i++;
135 +            wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
136 +            label_index += line_len + i;
137 +            i = 0;
138 +            break;
139 +          default:
140 +            i++;
141 +            break;
142 +        }
143 +        if ((i + line_len) == max_width)
144 +        {
145 +          wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
146 +          label_index = label_index + line_len + i;
147 +          i = 0;
148 +        }
149 +      }
150 +      wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
151 +    }
152 +    else
153 +    {
154 +      lines = 1;
155 +      wrapped_label = malloc(sizeof(*wrapped_label));
156 +      wrapped_label[0] = (char*)classification;
157 +    }
158 +
159 +    for (n = 0; n < lines; n++ )
160 +    {
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);
165 +        else
166 +        {
167 +          if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
168 +            putchar('\\');
169 +
170 +          printf("%c", *ptr);
171 +        }
172 +      if (i > longest)
173 +      {
174 +        longest = i;
175 +        longest_line = n;
176 +      }
177 +      printf(")put\n");
178 +    }
179 +
180 +   /*
181 +    * For LSPP use a fixed width font so that line wrapping can be calculated
182 +    */
183 +
184 +    puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
185 +
186 +   /*
187 +    * Finally, the procedure to write the labels on the page...
188 +    */
189 +
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++)
195 +      printf(" dup");
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 ++)
207 +    {
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);
211 +    }
212 +    printf("  pop\n"
213 +           "}bind put\n");
214 +
215 +   /*
216 +    * Do some clean up at the end of the LSPP special case
217 +    */
218 +    free(wrapped_label);
219 +
220 +  }
221 +  else
222 +  {
223 +#endif /* !WITH_LSPP */
224 +  
225   /*
226    * Set the classification + page label string...
227    */
228 @@ -395,7 +531,10 @@ WriteLabelProlog(const char *label,        /* I
229    printf("  %.0f moveto ESPpl show\n", top - 14.0);
230    puts("pop");
231    puts("}bind put");
232 +  }
233 +#ifdef WITH_LSPP
234  }
235 +#endif /* WITH_LSPP */
236  
237  
238  /*
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,    /*
243  {
244    const char   *classification;        /* CLASSIFICATION environment variable */
245    const char   *ptr;                   /* Temporary string pointer */
246 +#ifdef WITH_LSPP
247 +  int           i,                      /* counter */
248 +                n,                      /* 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 */
258  
259  
260   /*
261 @@ -3192,6 +3204,124 @@ write_label_prolog(pstops_doc_t *doc,   /*
262      return;
263    }
264  
265 +#ifdef WITH_LSPP
266 +  if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
267 +  {
268 +   /*
269 +    * Based on the 12pt fixed width font below determine the max_width
270 +    */
271 +    max_width = width / 8;
272 +    longest_line = 0;
273 +    longest = 0;
274 +    classification += 5; // Skip the "LSPP:"
275 +    label_len = strlen(classification);
276 +
277 +    if (label_len > max_width)
278 +    {
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])
284 +      {
285 +        if ((label_index + line_len) > label_len)
286 +          break;
287 +        switch (classification[label_index + line_len + i])
288 +        {
289 +          case ':':
290 +          case ',':
291 +          case '-':
292 +            i++;
293 +            wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
294 +            label_index += line_len + i;
295 +            i = 0;
296 +            break;
297 +          default:
298 +            i++;
299 +            break;
300 +        }
301 +        if ((i + line_len) == max_width)
302 +        {
303 +          wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
304 +          label_index = label_index + line_len + i;
305 +          i = 0;
306 +        }
307 +      }
308 +      wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
309 +    }
310 +    else
311 +    {
312 +      lines = 1;
313 +      wrapped_label = malloc(sizeof(*wrapped_label));
314 +      wrapped_label[0] = (char*)classification;
315 +    }
316 +
317 +    for (n = 0; n < lines; n++ )
318 +    {
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);
323 +        else
324 +        {
325 +          if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
326 +            putchar('\\');
327 +
328 +          printf("%c", *ptr);
329 +        }
330 +      if (i > longest)
331 +      {
332 +        longest = i;
333 +        longest_line = n;
334 +      }
335 +      printf(")put\n");
336 +    }
337 +
338 +   /*
339 +    * For LSPP use a fixed width font so that line wrapping can be calculated
340 +    */
341 +
342 +    puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
343 +
344 +   /*
345 +    * Finally, the procedure to write the labels on the page...
346 +    */
347 +
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++)
353 +      printf(" dup");
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 ++)
365 +    {
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);
369 +    }
370 +    printf("  pop\n"
371 +           "}bind put\n");
372 +
373 +   /*
374 +    * Do some clean up at the end of the LSPP special case
375 +    */
376 +    free(wrapped_label);
377 +
378 +  }
379 +  else
380 +  {
381 +#endif /* !WITH_LSPP */
382 +
383   /*
384    * Set the classification + page label string...
385    */
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");
390 +  }
391 +#ifdef WITH_LSPP
392  }
393 +#endif /* WITH_LSPP */
394  
395  
396  /*
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@
401  LDFLAGS                =       @LDFLAGS@
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@
408  OPTIM          =       @OPTIM@
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
412 @@ -19,12 +19,20 @@
413  #define _HTTP_NO_PRIVATE
414  #include "cupsd.h"
415  
416 +#ifndef _GNU_SOURCE
417 +#define _GNU_SOURCE
418 +#endif /* !defined(_GNU_SOURCE) */
419  #ifdef __APPLE__
420  #  include <libproc.h>
421  #endif /* __APPLE__ */
422  #ifdef HAVE_TCPD_H
423  #  include <tcpd.h>
424  #endif /* HAVE_TCPD_H */
425 +#ifdef WITH_LSPP
426 +#  include <selinux/selinux.h>
427 +#  include <selinux/context.h>
428 +#  include <fcntl.h>
429 +#endif /* WITH_LSPP */
430  
431  
432  /*
433 @@ -265,6 +273,59 @@ cupsdAcceptClient(cupsd_listener_t *lis)
434    }
435  #endif /* HAVE_TCPD_H */
436  
437 +#ifdef WITH_LSPP
438 +  if (is_lspp_config())
439 +  {
440 +    struct ucred cr;
441 +    unsigned int cl=sizeof(cr);
442 +
443 +    if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &cr, &cl) == 0)
444 +    {
445 +     /*
446 +      * client_pid_to_auid() can be racey
447 +      * In this case the pid is based on a socket connected to the client
448 +      */
449 +      if ((con->auid = client_pid_to_auid(cr.pid)) == -1)
450 +      {
451 +        httpClose(con->http);
452 +        cupsdLogClient(con, CUPSD_LOG_ERROR,
453 +                      "Unable to determine client auid for client pid=%d",
454 +                      cr.pid);
455 +        free(con);
456 +        return;
457 +      }
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);
461 +    }
462 +    else
463 +    {
464 +      httpClose(con->http);
465 +      cupsdLogClient(con, CUPSD_LOG_ERROR, "getsockopt() failed");
466 +      free(con);
467 +      return; 
468 +    }
469 +
470 +   /*
471 +    * get the context of the peer connection
472 +    */
473 +    if (getpeercon(httpGetFd(con->http), &con->scon))
474 +    {
475 +      httpClose(con->http);
476 +      cupsdLogClient(con, CUPSD_LOG_ERROR, "getpeercon() failed");
477 +      free(con);
478 +      return; 
479 +    }
480 +
481 +    cupsdLogClient(con, CUPSD_LOG_INFO, "client context=%s", con->scon);
482 +  }
483 +  else
484 +  {
485 +    cupsdLogClient(con, CUPSD_LOG_DEBUG, "skipping getpeercon()");
486 +    cupsdSetString(&con->scon, UNKNOWN_SL);
487 +  }
488 +#endif /* WITH_LSPP */
489 +
490  #ifdef AF_LOCAL
491    if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
492    {
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 */
497 +#ifdef WITH_LSPP
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 */
504  
505  
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);
509           }
510  
511 +#ifdef WITH_LSPP
512 +         if (strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
513 +         {
514 +           if (getfilecon(con->filename, &spoolcon) == -1)
515 +           {
516 +             cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
517 +             cupsdCloseClient(con);
518 +             return;
519 +           }
520 +           clicon = context_new(con->scon);
521 +           tmpcon = context_new(spoolcon);
522 +           freecon(spoolcon);
523 +           if (!clicon || !tmpcon)
524 +           {
525 +             cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
526 +             if (clicon)
527 +               context_free(clicon);
528 +             if (tmpcon)
529 +               context_free(tmpcon);
530 +             cupsdCloseClient(con);
531 +             return;
532 +           }
533 +           clirange = (char *) context_range_get(clicon);
534 +           if (clirange)
535 +           {
536 +             clirange = strdup(clirange);
537 +             if ((cliclearance = strtok(clirange, "-")) != NULL)
538 +             {
539 +               if (context_range_set(tmpcon, cliclearance) == -1)
540 +               {
541 +                 cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
542 +                 free(clirange);
543 +                 context_free(tmpcon);
544 +                 context_free(clicon);
545 +                 cupsdCloseClient(con);
546 +                 return;
547 +               }
548 +             }
549 +             else
550 +             {
551 +               if (context_range_set(tmpcon, (context_range_get(clicon))) == -1)
552 +               {
553 +                 cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
554 +                 free(clirange);
555 +                 context_free(tmpcon);
556 +                 context_free(clicon);
557 +                 cupsdCloseClient(con);
558 +                 return;
559 +               }
560 +             }
561 +             free(clirange);
562 +           }
563 +           if (setfilecon(con->filename, context_str(tmpcon)) == -1)
564 +           {
565 +             cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
566 +             context_free(tmpcon);
567 +             context_free(clicon);
568 +             cupsdCloseClient(con);
569 +             return;
570 +           }
571 +           cupsdLogClient(con, CUPSD_LOG_DEBUG2, "%s set to %s", 
572 +                          con->filename, context_str(tmpcon));
573 +           context_free(tmpcon);
574 +           context_free(clicon);
575 +         }
576 +#endif /* WITH_LSPP */
577 +
578           if (httpGetState(con->http) != HTTP_STATE_POST_SEND)
579           {
580             if (!httpWait(con->http, 0))
581 @@ -3174,6 +3309,49 @@ is_path_absolute(const char *path)       /* I
582    return (1);
583  }
584  
585 +#ifdef WITH_LSPP
586 +/*
587 + * 'client_pid_to_auid()' - Using the client's pid, read /proc and determine the loginuid.
588 + */
589 +
590 +uid_t client_pid_to_auid(pid_t clipid)
591 +{
592 +  uid_t uid;
593 +  int len, in;
594 +  char buf[16] = {0};
595 +  char fname[32] = {0};
596 +
597 +
598 + /*
599 +  * Hopefully this pid is still the one we are interested in.
600 +  */
601 +  snprintf(fname, 32, "/proc/%d/loginuid", clipid);
602 +  in = open(fname, O_NOFOLLOW|O_RDONLY);
603 +
604 +  if (in < 0)
605 +    return (uid_t) -1;
606 +
607 +  errno = 0;
608 +
609 +  do {
610 +    len = read(in, buf, sizeof(buf));
611 +  } while (len < 0 && errno == EINTR);
612 +
613 +  close(in);
614 +
615 +  if (len < 0 || len >= sizeof(buf))
616 +    return (uid_t) -1;
617 +
618 +  errno = 0;
619 +  buf[len] = 0;
620 +  uid = strtol(buf, 0, 10);
621 +
622 +  if (errno != 0)
623 +    return (uid_t) -1;
624 +  else
625 +    return uid;
626 +}
627 +#endif /* WITH_LSPP */
628  
629  /*
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
634 @@ -13,6 +13,13 @@
635  #endif /* HAVE_AUTHORIZATION_H */
636  
637  
638 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
639 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
640 +
641 +#ifdef WITH_LSPP
642 +#include <selinux/selinux.h>
643 +#endif /* WITH_LSPP */
644 +
645  /*
646   * HTTP client structure...
647   */
648 @@ -63,6 +70,10 @@ struct cupsd_client_s
649  #ifdef HAVE_AUTHORIZATION_H
650    AuthorizationRef     authref;        /* Authorization ref */
651  #endif /* HAVE_AUTHORIZATION_H */
652 +#ifdef WITH_LSPP
653 +  security_context_t   scon;           /* Security context of connection */
654 +  uid_t                        auid;           /* Audit loginuid of the client */
655 +#endif /* WITH_LSPP */
656  };
657  
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);
663 +#ifdef WITH_LSPP
664 +extern uid_t   client_pid_to_auid(pid_t clipid);
665 +#endif /* WITH_LSPP */
666  
667  #ifdef HAVE_SSL
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
672 @@ -37,6 +37,9 @@
673  #  define INADDR_NONE  0xffffffff
674  #endif /* !INADDR_NONE */
675  
676 +#ifdef WITH_LSPP
677 +#  include <libaudit.h>
678 +#endif /* WITH_LSPP */
679  
680  /*
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 },
686 +#ifdef WITH_LSPP
687 +  { "AuditLog",                        &AuditLog,              CUPSD_VARTYPE_INTEGER },
688 +  { "PerPageLabels",           &PerPageLabels,         CUPSD_VARTYPE_BOOLEAN },
689 +#endif /* WITH_LSPP */
690    { "WebInterface",            &WebInterface,          CUPSD_VARTYPE_BOOLEAN }
691  };
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 */
697 +#ifdef WITH_LSPP
698 +  char         *audit_message;         /* Audit message string */
699 +#endif /* WITH_LSPP */
700  
701  
702   /*
703 @@ -864,6 +874,25 @@ cupsdReadConfiguration(void)
704  
705    RunUser = getuid();
706  
707 +#ifdef WITH_LSPP
708 +  if (AuditLog != -1)
709 +  {
710 +   /*
711 +    * ClassifyOverride is set during read_configuration, if its ON, report it now
712 +    */
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);
717 +   /*
718 +    * PerPageLabel is set during read_configuration, if its OFF, report it now
719 +    */
720 +    if (!PerPageLabels)
721 +      audit_log_user_message(AuditLog, AUDIT_USYS_CONFIG,
722 +                "[Config] PerPageLabels=disabled", ServerName, NULL, NULL, 1);
723 +  }
724 +#endif /* WITH_LSPP */
725 +
726    cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
727                    RemotePort ? "enabled" : "disabled");
728  
729 @@ -1275,7 +1304,19 @@ cupsdReadConfiguration(void)
730      cupsdClearString(&Classification);
731  
732    if (Classification)
733 +  {
734      cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
735 +#ifdef WITH_LSPP
736 +    if (AuditLog != -1)
737 +    {
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);
743 +    }
744 +#endif /* WITH_LSPP */
745 +  }
746  
747   /*
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);
751  }
752  
753 +#ifdef WITH_LSPP
754 +int is_lspp_config()
755 +{
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));
760 +  else
761 +    return 0;
762 +}
763 +#endif /* WITH_LSPP */
764 +
765  
766  /*
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 */
774  
775 +#ifdef WITH_LSPP
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 */
781 +
782  #ifdef HAVE_ONDEMAND
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 */
788  
789 +#ifdef WITH_LSPP
790 +extern int             is_lspp_config(void);
791 +#endif /* WITH_LSPP */
792  
793  /*
794   * Prototypes...
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
798 @@ -8,6 +8,8 @@
799   * information.
800   */
801  
802 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
803 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
804  
805  /*
806   * Include necessary headers.
807 @@ -33,6 +35,14 @@
808  #  include <unistd.h>
809  #endif /* _WIN32 */
810  
811 +#include "config.h"
812 +#ifdef WITH_LSPP
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 */
818 +
819  #include "mime.h"
820  
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
825 @@ -11,6 +11,9 @@
826   * information.
827   */
828  
829 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
830 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
831 +
832  /*
833   * Include necessary headers...
834   */
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__ */
838  
839 +#ifdef WITH_LSPP
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 */
847  
848  /*
849   * Local functions...
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);
854 +#ifdef WITH_LSPP
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
861      "time-at-creation",
862      "time-at-processing"
863    };
864 +#ifdef WITH_LSPP
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 */
879  
880  
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
883  
884    attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
885  
886 +#ifdef WITH_LSPP
887 +  if (is_lspp_config())
888 +  {
889 +    if (!con->scon || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
890 +    {
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."));
893 +      return (NULL);
894 +    }
895 +
896 +   /*
897 +    * Perform an access check so that if the user gets feedback at enqueue time
898 +    */
899 +
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:");
903 +
904 +    if (printerfile != NULL)
905 +    {
906 +      cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: Attempting an access check on printer device %s",
907 +                      printerfile);
908 +
909 +      if (lstat(printerfile, &printerstat) < 0)
910 +      {
911 +       if (errno != ENOENT)
912 +       {
913 +         send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to stat the printer"));
914 +         return (NULL);
915 +       }
916 +       /*
917 +        * The printer does not exist, so for now assume it's a FileDevice
918 +        */
919 +       tclass = SECCLASS_FILE;
920 +       avr = FILE__WRITE;
921 +      }
922 +      else if (S_ISCHR(printerstat.st_mode))
923 +      {
924 +       tclass = SECCLASS_CHR_FILE;
925 +       avr = CHR_FILE__WRITE;
926 +      }
927 +      else if (S_ISREG(printerstat.st_mode))
928 +      {
929 +       tclass = SECCLASS_FILE;
930 +       avr = FILE__WRITE;
931 +      }
932 +      else
933 +      {
934 +       send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Printer is not a character device or regular file"));
935 +       return (NULL);
936 +      }
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)
942 +      {
943 +        send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the client"));
944 +        return (NULL);
945 +      }
946 +      if (getfilecon(printerfile, &devcon) == -1)
947 +      {
948 +        send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux context of the printer"));
949 +        return (NULL);
950 +      }
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);
955 +
956 +      if (avc_context_to_sid(devcon, &psid) != 0)
957 +      {
958 +        send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the printer"));
959 +        freecon(devcon);
960 +        return (NULL);
961 +      }
962 +      freecon(devcon);
963 +      if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
964 +      {
965 +       /*
966 +        * The access check failed, so cancel the job and send an audit message
967 +        */
968 +        if (AuditLog != -1)
969 +        {
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);
977 +        }
978 +
979 +        send_ipp_status(con, IPP_NOT_AUTHORIZED, _("SELinux prohibits access to the printer"));
980 +        return (NULL);
981 +      }
982 +    }
983 +  }
984 +#endif /* WITH_LSPP */
985 +
986    if ((job = cupsdAddJob(priority, printer->name)) == NULL)
987    {
988      send_ipp_status(con, IPP_INTERNAL_ERROR,
989 @@ -1576,6 +1705,32 @@ add_job(cupsd_client_t  *con,            /* I - Cl
990      return (NULL);
991    }
992  
993 +#ifdef WITH_LSPP
994 +  if (is_lspp_config())
995 +  {
996 +   /*
997 +    * duplicate the security context and auid of the connection into the job structure
998 +    */
999 +    job->scon = strdup(con->scon);
1000 +    job->auid = con->auid;
1001 +
1002 +   /* 
1003 +    * add the security context to the request so that on a restart the security
1004 +    * attributes will be able to be restored
1005 +    */
1006 +    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "security-context", 
1007 +                NULL, job->scon);
1008 +  }
1009 +  else
1010 +  {
1011 +   /*
1012 +    * Fill in the security context of the job as unlabeled
1013 +    */
1014 +    cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: setting context of job to %s", UNKNOWN_SL);
1015 +    cupsdSetString(&job->scon, UNKNOWN_SL);
1016 +  }
1017 +#endif /* WITH_LSPP */
1018 +
1019    job->dtype   = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
1020    job->attrs   = con->request;
1021    job->dirty   = 1;
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]);
1025      }
1026 +#ifdef WITH_LSPP
1027 +    else
1028 +    {
1029 +     /*
1030 +      * The option was present, so capture the user supplied strings
1031 +      */
1032 +      userheader = strdup(attr->values[0].string.text);
1033 +
1034 +      if (attr->num_values > 1)
1035 +        userfooter = strdup(attr->values[1].string.text);
1036 +
1037 +      if (Classification != NULL && (strcmp(userheader, Classification) == 0)
1038 +          && userfooter &&(strcmp(userfooter, Classification) == 0))
1039 +      {
1040 +       /*
1041 +        * Since both values are Classification, the user is not trying to Override
1042 +        */
1043 +        free(userheader);
1044 +        if (userfooter) free(userfooter);
1045 +        userheader = userfooter = NULL;
1046 +      }
1047 +    }
1048 +#endif /* WITH_LSPP */
1049  
1050      job->job_sheets = attr;
1051  
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);
1056 +#ifdef WITH_LSPP
1057 +         override = 1;
1058 +#endif /* WITH_LSPP */
1059         }
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);
1066 +#ifdef WITH_LSPP
1067 +         override = 1;
1068 +#endif /* WITH_LSPP */
1069         }
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);
1076 +#ifdef WITH_LSPP
1077 +         override = 1;
1078 +#endif /* WITH_LSPP */
1079          }
1080        }
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);
1086 +#ifdef WITH_LSPP
1087 +       override = 1;
1088 +#endif /* WITH_LSPP */
1089 +      }
1090 +#ifdef WITH_LSPP
1091 +      if (is_lspp_config() && AuditLog != -1)
1092 +      {
1093 +        audit_message = NULL;
1094 +
1095 +        if (userheader || userfooter)
1096 +        {
1097 +          if (!override)
1098 +          {
1099 +           /*
1100 +            * The user overrode the banner, so audit it
1101 +            */
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);
1108 +         }
1109 +          else
1110 +          {
1111 +           /*
1112 +            * The user tried to override the banner, audit the failure
1113 +            */
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);
1120 +         }
1121 +          cupsdClearString(&audit_message);
1122 +       }
1123        }
1124 +
1125 +      if (userheader)
1126 +        free(userheader);
1127 +      if (userfooter)
1128 +        free(userfooter);
1129 +#endif /* WITH_LSPP */
1130      }
1131 +    
1132  
1133     /*
1134      * See if we need to add the starting sheet...
1135 @@ -3648,6 +3879,128 @@ check_rss_recipient(
1136  }
1137  
1138  
1139 +#ifdef WITH_LSPP
1140 +/*
1141 + * 'check_context()' - Check SELinux security context of a user and job
1142 + */
1143 +
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 */
1147 +{
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 */
1157 +
1158 +
1159 + /*
1160 +  * Validate the input to be sure there are contexts to work with...
1161 +  */
1162 +
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)
1166 +    return -1;
1167 +
1168 +  if ((enforcing = security_getenforce()) == -1)
1169 +  {
1170 +    cupsdLogJob(job, CUPSD_LOG_ERROR,
1171 +               "Error while determining SELinux enforcement");
1172 +    return -1;
1173 +  }
1174 +  cupsdLogJob(job, CUPSD_LOG_DEBUG,
1175 +             "check_context: client context %s job context %s",
1176 +             con->scon, job->scon);
1177 +
1178 +
1179 + /*
1180 +  * Initialize the avc engine...
1181 +  */
1182 +
1183 +  static int avc_initialized = 0;
1184 +  if (! avc_initialized++)
1185 +  {
1186 +    if (avc_init("cupsd", NULL, NULL, NULL, NULL) < 0)
1187 +    {
1188 +      cupsdLogJob(job, CUPSD_LOG_ERROR, "check_context: unable avc_init");
1189 +      return -1;
1190 +    } 
1191 +  } 
1192 +  if (avc_context_to_sid(con->scon, &clisid) != 0)
1193 +  {
1194 +    cupsdLogJob(job, CUPSD_LOG_ERROR,
1195 +               "check_context: unable to convert %s to SELinux sid",
1196 +               con->scon);
1197 +    return -1;
1198 +  }
1199 +  if (avc_context_to_sid(job->scon, &jobsid) != 0)
1200 +  {
1201 +    cupsdLogJob(job, CUPSD_LOG_ERROR,
1202 +               "check_context: unable to convert %s to SELinux sid",
1203 +               job->scon);
1204 +    return -1;
1205 +  }
1206 +  avc_entry_ref_init(&avcref);
1207 +  tclass = SECCLASS_FILE;
1208 +  avr = FILE__READ;
1209 +
1210 + /*
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...
1213 +  */
1214 +
1215 +  if (avc_has_perm_noaudit(clisid, jobsid, tclass, avr, &avcref, NULL) != 0)
1216 +  {
1217 +    cupsdLogJob(job, CUPSD_LOG_INFO,
1218 +               "check_context: SELinux denied access "
1219 +               "based on the client context");
1220 +
1221 +    snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
1222 +    if (getfilecon(filename, &spoolfilecon) == -1)
1223 +    {
1224 +      cupsdLogJob(job, CUPSD_LOG_ERROR,
1225 +                 "check_context: Unable to get spoolfile context");
1226 +      return -1;
1227 +    }
1228 +    if (avc_context_to_sid(spoolfilecon, &filesid) != 0)
1229 +    {
1230 +      cupsdLogJob(job, CUPSD_LOG_ERROR,
1231 +                 "check_context: Unable to determine the "
1232 +                 "SELinux sid for the spool file");
1233 +      freecon(spoolfilecon);
1234 +      return -1;
1235 +    }
1236 +    freecon(spoolfilecon);
1237 +    if (avc_has_perm_noaudit(clisid, filesid, tclass, avr, &avcref, NULL) != 0)
1238 +    {
1239 +      cupsdLogJob(job, CUPSD_LOG_INFO,
1240 +                 "check_context: SELinux denied access to the spool file");
1241 +      return 0;
1242 +    }
1243 +    cupsdLogJob(job, CUPSD_LOG_INFO,
1244 +               "check_context: SELinux allowed access to the spool file");
1245 +    return 1;
1246 +  }
1247 +  else
1248 +    if (enforcing == 0)
1249 +      cupsdLogJob(job, CUPSD_LOG_INFO,
1250 +                 "check_context: allowing operation due to permissive mode");
1251 +    else
1252 +      cupsdLogJob(job, CUPSD_LOG_INFO,
1253 +                 "check_context: SELinux allowed access based on the "
1254 +                 "client context");
1255 +
1256 +  return 1;
1257 +}
1258 +#endif /* WITH_LSPP */
1259 +
1260 +
1261  /*
1262   * 'check_quotas()' - Check quotas for a printer and user.
1263   */
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 */
1268 +#ifdef WITH_LSPP
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 */
1276 +
1277  
1278  
1279    cupsdLogMessage(CUPSD_LOG_DEBUG2,
1280 @@ -4138,6 +4500,85 @@ copy_banner(cupsd_client_t *con, /* I -
1281  
1282    fchmod(cupsFileNumber(out), 0640);
1283    fchown(cupsFileNumber(out), RunUser, Group);
1284 +#ifdef WITH_LSPP
1285 +  if (job->scon != NULL &&
1286 +      strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1287 +  {
1288 +    if (getfilecon(filename, &spoolcon) == -1)
1289 +    {
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 --;
1294 +      return (0);
1295 +    }
1296 +    tmpcon = context_new(spoolcon);
1297 +    jobcon = context_new(job->scon);
1298 +    freecon(spoolcon);
1299 +    if (!tmpcon || !jobcon)
1300 +    {
1301 +      if (tmpcon)
1302 +        context_free(tmpcon);
1303 +      if (jobcon)
1304 +        context_free(jobcon);
1305 +      cupsdLogJob(job, CUPSD_LOG_ERROR,
1306 +                 "copy_banner: Unable to get the SELinux contexts");
1307 +      job->num_files --;
1308 +      return (0);
1309 +    }
1310 +    jobrange = (char *) context_range_get(jobcon);
1311 +    if (jobrange)
1312 +    {
1313 +      jobrange = strdup(jobrange);
1314 +      if ((jobclearance = strtok(jobrange, "-")) != NULL)
1315 +      {
1316 +       if (context_range_set(tmpcon, jobclearance) == -1)
1317 +       {
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));
1322 +         free(jobrange);
1323 +         context_free(jobcon);
1324 +         context_free(tmpcon);
1325 +         job->num_files --;
1326 +         return (0);
1327 +       }
1328 +      }
1329 +      else
1330 +      {
1331 +       if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1332 +       {
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));
1337 +         free(jobrange);
1338 +         context_free(jobcon);
1339 +         context_free(tmpcon);
1340 +         job->num_files --;
1341 +         return (0);
1342 +       }
1343 +      }
1344 +      free(jobrange);
1345 +    }
1346 +    if (setfilecon(filename, context_str(tmpcon)) == -1)
1347 +    {
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 --;
1355 +      return (0);
1356 +    }
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);
1361 +  }
1362 +#endif /* WITH_LSPP */
1363  
1364   /*
1365    * Try the localized banner file under the subdirectory...
1366 @@ -4232,6 +4673,24 @@ copy_banner(cupsd_client_t *con, /* I -
1367        else
1368          s = attrname;
1369  
1370 +#ifdef WITH_LSPP
1371 +      if (strcmp(s, "mls-label") == 0)
1372 +      {
1373 +        if (job->scon != NULL && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1374 +        {
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);
1384 +        }
1385 +        continue;
1386 +      }
1387 +#endif /* WITH_LSPP */
1388        if (!strcmp(s, "printer-name"))
1389        {
1390          cupsFilePuts(out, job->dest);
1391 @@ -6439,6 +6898,22 @@ get_job_attrs(cupsd_client_t  *con,      /* I
1392  
1393    exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
1394  
1395 +
1396 +#ifdef WITH_LSPP
1397 + /*
1398 +  * Check SELinux...
1399 +  */
1400 +  if (is_lspp_config() && check_context(con, job) != 1)
1401 +  {
1402 +   /*
1403 +    * Unfortunately we have to lie to the user...
1404 +    */
1405 +    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
1406 +    return;
1407 +  }
1408 +#endif /* WITH_LSPP */
1409 +
1410 +
1411   /*
1412    * Copy attributes...
1413    */
1414 @@ -6836,6 +7311,11 @@ get_jobs(cupsd_client_t  *con,           /* I - C
1415        if (username[0] && _cups_strcasecmp(username, job->username))
1416         continue;
1417  
1418 +#ifdef WITH_LSPP
1419 +      if (is_lspp_config() && check_context(con, job) != 1)
1420 +       continue;
1421 +#endif /* WITH_LSPP */
1422 +
1423        if (count > 0)
1424         ippAddSeparator(con->response);
1425  
1426 @@ -11445,6 +11925,11 @@ validate_user(cupsd_job_t    *job,     /* I
1427  
1428    strlcpy(username, get_username(con), userlen);
1429  
1430 +#ifdef WITH_LSPP
1431 +  if (is_lspp_config() && check_context(con, job) != 1)
1432 +    return 0;
1433 +#endif /* WITH_LSPP */
1434 +
1435   /*
1436    * Check the username against the owner...
1437    */
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
1441 @@ -8,6 +8,9 @@
1442   * information.
1443   */
1444  
1445 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1446 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1447 +
1448  /*
1449   * Include necessary headers...
1450   */
1451 @@ -23,6 +26,14 @@
1452  #  endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
1453  #endif /* __APPLE__ */
1454  
1455 +#ifdef WITH_LSPP
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 */
1463  
1464  /*
1465   * Design Notes for Job Management
1466 @@ -544,6 +555,14 @@ cupsdContinueJob(cupsd_job_t *job) /* I
1467                                         /* PRINTER_STATE_REASONS env var */
1468                         rip_max_cache[255];
1469                                         /* RIP_MAX_CACHE env variable */
1470 +#ifdef WITH_LSPP
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
1474 +                                                  env var */
1475 +  const char           *mls_label = NULL;      /* SL to put in classification
1476 +                                                  env var */
1477 +#endif /* WITH_LSPP */
1478  
1479  
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;
1484  
1485 +#ifdef WITH_LSPP
1486 +  if (is_lspp_config())
1487 +  {
1488 +    if (!job->scon || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
1489 +    {
1490 +      if (AuditLog != -1)
1491 +      {
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);
1498 +      }
1499 +    }
1500 +    else 
1501 +    {
1502 +      jobcon = context_new(job->scon);
1503 +
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);
1509 +      else
1510 +        label_template = strdup(attr->values[0].string.text);
1511 +
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);
1518 +      else
1519 +        mls_label = label_template;
1520 +
1521 +      if (mls_label && (PerPageLabels || banner_page))
1522 +      {
1523 +        snprintf(classification, sizeof(classification), "CLASSIFICATION=LSPP:%s", mls_label);
1524 +        envp[envc ++] = classification;
1525 +      }
1526 +
1527 +      if ((AuditLog != -1) && !banner_page)
1528 +      {
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);
1536 +      }
1537 +      context_free(jobcon);
1538 +      free(label_template);
1539 +    }
1540 +  }
1541 +  else
1542 +   /*
1543 +    * Fall through to the non-LSPP behavior
1544 +    */
1545 +#endif /* WITH_LSPP */
1546    if (Classification && !banner_page)
1547    {
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");
1551    }
1552  
1553 +#ifdef WITH_LSPP
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())
1557 +  {
1558 +   /*
1559 +    * There was no security context so delete the job
1560 +    */
1561 +    cupsdLogJob(job, CUPSD_LOG_ERROR,
1562 +               "Missing or bad security-context attribute "
1563 +               "in control file \"%s\"!",
1564 +               jobfile);
1565 +    goto error;
1566 +  }
1567 +#endif /* WITH_LSPP */
1568 +
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
1573  {
1574    char         filename[1024];         /* Job control filename */
1575    cups_file_t  *fp;                    /* Job file */
1576 +#ifdef WITH_LSPP
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 */
1584  
1585  
1586    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
1587 @@ -2295,6 +2399,78 @@ cupsdSaveJob(cupsd_job_t *job)           /* I - J
1588  
1589    fchown(cupsFileNumber(fp), RunUser, Group);
1590  
1591 +#ifdef WITH_LSPP
1592 +  if (job->scon && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
1593 +  {
1594 +    if (getfilecon(filename, &spoolcon) == -1)
1595 +    {
1596 +      cupsdLogJob(job, CUPSD_LOG_ERROR,
1597 +                 "Unable to get context of job control file \"%s\" - %s.",
1598 +                 filename, strerror(errno));
1599 +      return;
1600 +    }
1601 +    jobcon = context_new(job->scon);
1602 +    tmpcon = context_new(spoolcon);
1603 +    freecon(spoolcon);
1604 +    if (!jobcon || !tmpcon)
1605 +    {
1606 +      if (jobcon)
1607 +        context_free(jobcon);
1608 +      if (tmpcon)
1609 +        context_free(tmpcon);
1610 +      cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to get SELinux contexts");
1611 +      return;
1612 +    }
1613 +    jobrange = context_range_get(jobcon);
1614 +    if (jobrange)
1615 +    {
1616 +      jobrange_copy = strdup(jobrange);
1617 +      if ((jobclearance = strtok(jobrange_copy, "-")) != NULL)
1618 +      {
1619 +       if (context_range_set(tmpcon, jobclearance) == -1)
1620 +       {
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);
1628 +         return;
1629 +       }
1630 +      }
1631 +      else
1632 +      {
1633 +       if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
1634 +       {
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);
1642 +         return;
1643 +       }
1644 +      }
1645 +      free(jobrange_copy);
1646 +    }
1647 +    if (setfilecon(filename, context_str(tmpcon)) == -1)
1648 +    {
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);
1654 +      return;
1655 +    }
1656 +    cupsdLogJob(job, CUPSD_LOG_DEBUG2, "New spool file context=%s",
1657 +                context_str(tmpcon));
1658 +    context_free(tmpcon);
1659 +    context_free(jobcon);
1660 +  }
1661 +#endif /* WITH_LSPP */
1662 +
1663    job->attrs->state = IPP_IDLE;
1664  
1665    if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
1666 @@ -3995,6 +4171,19 @@ get_options(cupsd_job_t *job,            /* I - Jo
1667           banner_page)
1668          continue;
1669  
1670 +#ifdef WITH_LSPP
1671 +     /*
1672 +      * In LSPP mode refuse to honor the page-label
1673 +      */
1674 +      if (is_lspp_config() &&
1675 +          !strcmp(attr->name, "page-label"))
1676 +      {
1677 +        cupsdLogJob(job, CUPSD_LOG_DEBUG,
1678 +                   "Ignoring page-label option due to LSPP mode");
1679 +        continue;
1680 +      }
1681 +#endif /* WITH_LSPP */
1682 +
1683       /*
1684        * Otherwise add them to the list...
1685        */
1686 @@ -4805,6 +4994,18 @@ start_job(cupsd_job_t     *job,          /* I -
1687            cupsd_printer_t *printer)    /* I - Printer to print job */
1688  {
1689    const char   *filename;              /* Support filename */
1690 +#ifdef WITH_LSPP
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,
1703                                                    "job-cancel-after",
1704                                                    IPP_TAG_INTEGER);
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);
1708  
1709 +#ifdef WITH_LSPP
1710 +  if (is_lspp_config())
1711 +  {
1712 +   /*
1713 +    * Perform an access check before printing, but only if the printer starts with /dev/
1714 +    */
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:");
1718 +
1719 +    if (printerfile != NULL)
1720 +    {
1721 +      cupsdLogJob(job, CUPSD_LOG_DEBUG,
1722 +                 "Attempting to check access on printer device %s",
1723 +                 printerfile);
1724 +      if (lstat(printerfile, &printerstat) < 0)
1725 +      {
1726 +       if (errno != ENOENT)
1727 +       {
1728 +         cupsdLogJob(job, CUPSD_LOG_ERROR,
1729 +                     "Unable to stat the printer");
1730 +         cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1731 +         return ;
1732 +       }
1733 +       /*
1734 +        * The printer does not exist, so for now assume it's a FileDevice
1735 +        */
1736 +       tclass = SECCLASS_FILE;
1737 +       avr = FILE__WRITE;
1738 +      }
1739 +      else if (S_ISCHR(printerstat.st_mode))
1740 +      {
1741 +       tclass = SECCLASS_CHR_FILE;
1742 +       avr = CHR_FILE__WRITE;
1743 +      }
1744 +      else if (S_ISREG(printerstat.st_mode))
1745 +      {
1746 +       tclass = SECCLASS_FILE;
1747 +       avr = FILE__WRITE;
1748 +      }
1749 +      else
1750 +      {
1751 +       cupsdLogJob(job, CUPSD_LOG_ERROR,
1752 +                   "StartJob: Printer is not a character device or "
1753 +                   "regular file");
1754 +       cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1755 +       return ;
1756 +      }
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)
1762 +      {
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);
1766 +        return ;
1767 +      }
1768 +      if (getfilecon(printerfile, &devcon) == -1)
1769 +      {
1770 +        cupsdLogJob(job, CUPSD_LOG_ERROR,
1771 +                   "Unable to get the SELinux context of %s",
1772 +                   printerfile);
1773 +        cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1774 +        return ;
1775 +      }
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);
1781 +
1782 +      if (avc_context_to_sid(devcon, &psid) != 0)
1783 +      {
1784 +        cupsdLogJob(job, CUPSD_LOG_ERROR,
1785 +                   "Unable to determine the SELinux sid for the printer");
1786 +        freecon(devcon);
1787 +        cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1788 +        return ;
1789 +      }
1790 +      freecon(devcon);
1791 +
1792 +      if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
1793 +      {
1794 +       /*
1795 +        * The access check failed, so cancel the job and send an audit message
1796 +        */
1797 +        if (AuditLog != -1)
1798 +        {
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);
1806 +        }
1807 +
1808 +        cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
1809 +
1810 +        return ;
1811 +      }
1812 +    }
1813 +  }
1814 +#endif /* WITH_LSPP */
1815 +
1816   /*
1817    * Now start the first file in the job...
1818    */
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
1822 @@ -7,6 +7,13 @@
1823   * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
1824   */
1825  
1826 +/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
1827 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1828 +
1829 +#ifdef WITH_LSPP
1830 +#include <selinux/selinux.h>
1831 +#endif /* WITH_LSPP */
1832 +
1833  /*
1834   * Constants...
1835   */
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 */
1840 +#ifdef WITH_LSPP
1841 +  security_context_t   scon;           /* Security context of job */
1842 +  uid_t                        auid;           /* Audit loginuid for this job */
1843 +#endif /* WITH_LSPP */
1844  };
1845  
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
1850 @@ -57,6 +57,9 @@
1851  #  include <sys/param.h>
1852  #endif /* HAVE_SYS_PARAM_H */
1853  
1854 +#ifdef WITH_LSPP
1855 +#  include <libaudit.h>
1856 +#endif /* WITH_LSPP */
1857  
1858  /*
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 */
1864 +#if WITH_LSPP
1865 +  auditfail_t           failmode;       /* Action for audit_open failure */
1866 +#endif /* WITH_LSPP */
1867  #ifdef __APPLE__
1868    int                  use_sysman = 1; /* Use system management functions? */
1869  #else
1870 @@ -495,6 +501,25 @@ main(int  argc,                            /* I - Number of comm
1871      exit(errno);
1872    }
1873  
1874 +#ifdef WITH_LSPP
1875 +  if ((AuditLog = audit_open()) < 0 )
1876 +  {
1877 +    if (get_auditfail_action(&failmode) == 0)
1878 +    {
1879 +      if (failmode == FAIL_LOG)
1880 +      {
1881 +        cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to connect to audit subsystem.");
1882 +        AuditLog = -1;
1883 +      }
1884 +      else if (failmode == FAIL_TERMINATE)
1885 +      {
1886 +        fprintf(stderr, "cupsd: unable to start auditing, terminating");
1887 +        return -1;
1888 +      }
1889 +    }
1890 +  }
1891 +#endif /* WITH_LSPP */
1892 +
1893   /*
1894    * Let the system know we are busy while we bring up cupsd...
1895    */
1896 @@ -1201,6 +1226,11 @@ main(int  argc,                          /* I - Number of comm
1897  
1898    cupsdStopSelect();
1899  
1900 +#ifdef WITH_LSPP
1901 +  if (AuditLog != -1)
1902 +    audit_close(AuditLog);
1903 +#endif /* WITH_LSPP */
1904 +
1905    return (!stop_scheduler);
1906  }
1907  
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
1911 @@ -8,6 +8,8 @@
1912   * information.
1913   */
1914  
1915 +/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
1916 +
1917  /*
1918   * Include necessary headers...
1919   */
1920 @@ -32,6 +34,10 @@
1921  #  include <asl.h>
1922  #endif /* __APPLE__ */
1923  
1924 +#ifdef WITH_LSPP
1925 +#  include <libaudit.h>
1926 +#  include <selinux/context.h>
1927 +#endif /* WITH_LSPP */
1928  
1929  /*
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 */
1935 +#ifdef WITH_LSPP
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 */
1942  
1943  
1944   /*
1945 @@ -2378,6 +2391,45 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
1946        attr->values[1].string.text = _cupsStrAlloc(Classification ?
1947                                            Classification : p->job_sheets[1]);
1948      }
1949 +#ifdef WITH_LSPP
1950 +    if (AuditLog != -1)
1951 +    {
1952 +      audit_message = NULL;
1953 +      rangestr = NULL;
1954 +      printercon = 0;
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:");
1958 +
1959 +      if (printerfile != NULL)
1960 +      {
1961 +        if (getfilecon(printerfile, &devcon) == -1)
1962 +        {
1963 +          if(is_selinux_enabled())
1964 +            cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetPrinterAttrs: Unable to get printer context");
1965 +        }
1966 +        else
1967 +        {
1968 +          printercon = context_new(devcon);
1969 +          freecon(devcon);
1970 +        }
1971 +      }
1972 +
1973 +      if (printercon && context_range_get(printercon))
1974 +        rangestr = strdup(context_range_get(printercon));
1975 +      else
1976 +        rangestr = strdup("unknown");
1977 +
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);
1982 +      if (printercon)
1983 +        context_free(printercon);
1984 +      free(rangestr);
1985 +      cupsdClearString(&audit_message);
1986 +    }
1987 +#endif /* WITH_LSPP */
1988    }
1989  
1990    p->raw    = 0;
This page took 0.214145 seconds and 4 git commands to generate.