1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Add TSOL banner, trailer, page header/footers to a print job
29 */
30
31 /* system header files */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <limits.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <locale.h>
41 #include <tsol/label.h>
42
43 /* typedefs */
44
45 typedef int BOOL;
46
47 /* constants */
48
49 #ifndef FALSE
50 #define FALSE 0
51 #endif
52 #ifndef TRUE
53 #define TRUE 1
54 #endif
55
56 #define ME "lp.tsol_separator"
57 #define POSTSCRIPTLIB "/usr/lib/lp/postscript"
58 #define SEPARATORPS "tsol_separator.ps"
59 #define BANNERPS "tsol_banner.ps"
60 #define TRAILERPS "tsol_trailer.ps"
61 #define MAXUSERLEN 32
62 #define MAXHOSTLEN 32
63
64 /* external variables */
65
66 int optind; /* Used by getopt */
67 char *optarg; /* Used by getopt */
68
69 /* prototypes for static functions */
70
71 static int ProcessArgs(int argc, char **argv);
72 static void Usage(void);
73 static void ParseUsername(char *input, char *user, char *host);
74 static void EmitPSFile(const char *name);
75 static BOOL EmitFile(FILE *file);
76 static void EmitJobData(void);
77 static void EmitPrologue(void);
78 static void EmitCommandLineInfo(void);
79 static void EmitClockBasedInfo(void);
80 static void EmitLabelInfo(void);
81 static void CopyStdin(void);
82
83 /* static variables */
84
85 static char *ArgSeparatorPS;
86 static char *ArgBannerPS;
87 static char *ArgTrailerPS;
88 static char *ArgPSLib;
89 static char *ArgPrinter;
90 static char *ArgJobID;
91 static char *ArgUser;
92 static char *ArgTitle;
93 static char *ArgFile;
94 static BOOL ArgReverse;
95 static BOOL ArgNoPageLabels;
96 static int ArgDebugLevel;
97 static FILE *ArgLogFile;
98 static m_label_t *FileLabel;
99 static char *remoteLabel;
100
101 int
main(int argc,char * argv[])102 main(int argc, char *argv[])
103 {
104 int err;
105 /*
106 * Run immune from typical interruptions, so that
107 * we stand a chance to get the fault message.
108 * EOF (or startup error) is the only way out.
109 */
110 (void) signal(SIGHUP, SIG_IGN);
111 (void) signal(SIGINT, SIG_IGN);
112 (void) signal(SIGQUIT, SIG_IGN);
113 (void) signal(SIGTERM, SIG_IGN);
114
115 (void) setlocale(LC_ALL, "");
116 #if !defined(TEXT_DOMAIN)
117 #define TEXT_DOMAIN "SYS_TEST"
118 #endif
119 (void) textdomain(TEXT_DOMAIN);
120
121 if (ProcessArgs(argc, argv) != 0)
122 exit(1);
123
124 if ((FileLabel = m_label_alloc(MAC_LABEL)) == NULL)
125 exit(1);
126 /*
127 * If the job was submitted via remotely, the label of the
128 * remote peer will be set in the SLABEL environment variable
129 * by copying it out of the SECURE structure.
130 *
131 * If there is no SLABEL value, the job was submitted locally
132 * via the named pipe, and the file label can be determined
133 * from its pathname.
134 */
135 if ((remoteLabel = getenv("SLABEL")) != NULL) {
136 m_label_free(FileLabel);
137 FileLabel = NULL;
138 if (str_to_label(remoteLabel, &FileLabel, MAC_LABEL,
139 L_NO_CORRECTION, &err) == -1) {
140 perror("str_to_label");
141 exit(1);
142 }
143 } else if (getlabel(ArgFile, FileLabel) != 0) {
144 (void) fprintf(ArgLogFile,
145 gettext("%1$s: cannot get label of %2$s: %3$s\n"),
146 ME, ArgFile, strerror(errno));
147 exit(1);
148 }
149
150 /* All of these functions exit if they encounter an error */
151 EmitJobData();
152 EmitPSFile(ArgSeparatorPS);
153 if (ArgReverse)
154 EmitPSFile(ArgTrailerPS);
155 else
156 EmitPSFile(ArgBannerPS);
157 CopyStdin();
158 if (ArgReverse)
159 EmitPSFile(ArgBannerPS);
160 else
161 EmitPSFile(ArgTrailerPS);
162 if (ArgDebugLevel >= 1)
163 (void) fprintf(ArgLogFile, gettext("Done.\n"));
164 m_label_free(FileLabel);
165 return (0);
166 }
167
168 static void
EmitJobData(void)169 EmitJobData(void)
170 {
171 EmitPrologue();
172 EmitCommandLineInfo();
173 EmitClockBasedInfo();
174 EmitLabelInfo();
175
176 /* Emit ending PostScript code */
177 (void) printf("end\n\n");
178 (void) printf("%%%% End of code generated by lp.tsol_separator\n\n");
179
180 }
181
182 static void
EmitPrologue(void)183 EmitPrologue(void)
184 {
185 /* Emit preliminary PostScript code */
186 (void) printf("%%!\n\n");
187 (void) printf("%%%% Begin code generated by lp.tsol_separator\n\n");
188
189 (void) printf("%%%% Create JobDict if it doesn't exist\n");
190 (void) printf("userdict /JobDict known not {\n");
191 (void) printf(" userdict /JobDict 100 dict put\n");
192 (void) printf("} if\n\n");
193
194 (void) printf("%%%% Define job parameters, including TSOL security "
195 "info\n");
196 (void) printf("JobDict\n");
197 (void) printf("begin\n");
198 }
199
200 /* Emit parameters obtained from command line options */
201
202 static void
EmitCommandLineInfo(void)203 EmitCommandLineInfo(void)
204 {
205 char user[MAXUSERLEN + 1];
206 char host[MAXHOSTLEN + 1];
207
208 (void) printf("\t/Job_Printer (%s) def\n", ArgPrinter);
209 ParseUsername(ArgUser, user, host);
210 (void) printf("\t/Job_Host (%s) def\n", host);
211 (void) printf("\t/Job_User (%s) def\n", user);
212 (void) printf("\t/Job_JobID (%s) def\n", ArgJobID);
213 (void) printf("\t/Job_Title (%s) def\n", ArgTitle);
214 (void) printf("\t/Job_DoPageLabels (%s) def\n",
215 ArgNoPageLabels ? "NO" : "YES");
216 (void) printf("\n");
217 }
218
219 /* Emit parameters generated from the system clock */
220
221 static void
EmitClockBasedInfo(void)222 EmitClockBasedInfo(void)
223 {
224 char timebuf[80];
225 struct timeval clockval;
226
227 (void) gettimeofday(&clockval, NULL);
228 (void) strftime(timebuf, sizeof (timebuf), NULL,
229 localtime(&clockval.tv_sec));
230 (void) printf("\t/Job_Date (%s) def\n", timebuf);
231 (void) printf("\t/Job_Hash (%ld) def\n", clockval.tv_usec % 100000L);
232 (void) printf("\n");
233 }
234
235 /* Emit parameters derived from the SL and IL of the file being printed. */
236
237 static void
EmitLabelInfo(void)238 EmitLabelInfo(void)
239 {
240 char *header = NULL; /* DIA banner page fields */
241 char *label = NULL;
242 char *caveats = NULL;
243 char *channels = NULL;
244 char *page_label = NULL; /* interior pages label */
245
246 if (label_to_str(FileLabel, &header, PRINTER_TOP_BOTTOM,
247 DEF_NAMES) != 0) {
248 (void) fprintf(ArgLogFile,
249 gettext("%s: label_to_str PRINTER_TOP_BOTTOM: %s.\n"),
250 ME, strerror(errno));
251 exit(1);
252 }
253 if (label_to_str(FileLabel, &label, PRINTER_LABEL,
254 DEF_NAMES) != 0) {
255 (void) fprintf(ArgLogFile,
256 gettext("%s: label_to_str PRINTER_LABEL: %s.\n"),
257 ME, strerror(errno));
258 exit(1);
259 }
260 if (label_to_str(FileLabel, &caveats, PRINTER_CAVEATS,
261 DEF_NAMES) != 0) {
262 (void) fprintf(ArgLogFile,
263 gettext("%s: label_to_str PRINTER_CAVEATS: %s.\n"),
264 ME, strerror(errno));
265 exit(1);
266 }
267 if (label_to_str(FileLabel, &channels, PRINTER_CHANNELS,
268 DEF_NAMES) != 0) {
269 (void) fprintf(ArgLogFile,
270 gettext("%s: label_to_str PRINTER_CHANNELS: %s.\n"),
271 ME, strerror(errno));
272 exit(1);
273 }
274 if (label_to_str(FileLabel, &page_label, M_LABEL,
275 LONG_NAMES) != 0) {
276 (void) fprintf(ArgLogFile,
277 gettext("%s: label_to_str M_LABEL: %s.\n"),
278 ME, strerror(errno));
279 exit(1);
280 }
281
282 (void) printf("\t/Job_Classification (%s) def\n", header);
283 (void) printf("\t/Job_Protect (%s) def\n", label);
284 (void) printf("\t/Job_Caveats (%s) def\n", caveats);
285 (void) printf("\t/Job_Channels (%s) def\n", channels);
286 (void) printf("\t/Job_SL_Internal (%s) def\n", page_label);
287
288 /* Free memory allocated label_to_str */
289 free(header);
290 free(label);
291 free(caveats);
292 free(channels);
293 free(page_label);
294 }
295
296 /*
297 * Parse input "host!user" to separate host and user names.
298 */
299
300 static void
ParseUsername(char * input,char * user,char * host)301 ParseUsername(char *input, char *user, char *host)
302 {
303 char *cp;
304
305 if ((cp = strchr(input, '@')) != NULL) {
306 /* user@host */
307 (void) strlcpy(host, cp + 1, MAXHOSTLEN + 1);
308 *cp = '\0';
309 (void) strlcpy(user, input, MAXUSERLEN + 1);
310 *cp = '@';
311 } else if ((cp = strchr(input, '!')) != NULL) {
312 /* host!user */
313 (void) strlcpy(user, cp + 1, MAXUSERLEN + 1);
314 *cp = '\0';
315 (void) strlcpy(host, input, MAXHOSTLEN + 1);
316 *cp = '!';
317 } else {
318 /* user */
319 (void) strlcpy(user, input, MAXUSERLEN + 1);
320 host[0] = '\0';
321 }
322 }
323
324
325 static void
CopyStdin(void)326 CopyStdin(void)
327 {
328 if (!EmitFile(stdin)) {
329 (void) fprintf(ArgLogFile,
330 gettext("%s: Error copying stdin to stdout\n"), ME);
331 exit(1);
332 }
333 }
334
335
336 static BOOL
EmitFile(FILE * file)337 EmitFile(FILE *file)
338 {
339 int len;
340 #define BUFLEN 1024
341 char buf[BUFLEN];
342
343 while ((len = fread(buf, 1, BUFLEN, file)) > 0) {
344 if (fwrite(buf, 1, len, stdout) != len)
345 return (FALSE);
346 }
347 if (!feof(file))
348 return (FALSE);
349 return (TRUE);
350 }
351
352
353 static void
EmitPSFile(const char * name)354 EmitPSFile(const char *name)
355 {
356 char path[PATH_MAX];
357 FILE *file;
358 BOOL emitted;
359
360 if (name[0] != '/') {
361 (void) strlcpy(path, ArgPSLib, sizeof (path));
362 (void) strlcat(path, "/", sizeof (path));
363 (void) strlcat(path, name, sizeof (path));
364 } else {
365 (void) strlcpy(path, name, sizeof (path));
366 }
367
368 file = fopen(path, "r");
369 if (file == NULL) {
370 (void) fprintf(ArgLogFile,
371 gettext("%s: Error opening PostScript file %s. %s.\n"),
372 ME, path, strerror(errno));
373 exit(1);
374 }
375
376 emitted = EmitFile(file);
377 (void) fclose(file);
378 if (!emitted) {
379 (void) fprintf(ArgLogFile, gettext(
380 "%s: Error copying PostScript file %s to stdout.\n"),
381 ME, path);
382 exit(1);
383 }
384 }
385
386
387 static int
ProcessArgs(int argc,char * argv[])388 ProcessArgs(int argc, char *argv[])
389 {
390 int option_letter;
391 char *options_string = "lrd:e:s:b:t:L:";
392
393 /* set default values for arguments */
394 ArgSeparatorPS = SEPARATORPS;
395 ArgBannerPS = BANNERPS;
396 ArgTrailerPS = TRAILERPS;
397 ArgPSLib = POSTSCRIPTLIB;
398 ArgNoPageLabels = ArgReverse = FALSE;
399 ArgDebugLevel = 0;
400 ArgLogFile = stderr;
401
402 /* read switch arguments once to get error log file */
403 while ((option_letter = getopt(argc, argv, options_string)) != EOF) {
404 switch (option_letter) {
405 case 'd':
406 ArgDebugLevel = atoi(optarg);
407 break;
408 case 'e':
409 ArgLogFile = fopen(optarg, "a");
410 if (ArgLogFile == NULL) {
411 (void) fprintf(stderr,
412 gettext("Cannot open log file %s\n"),
413 optarg);
414 return (-1);
415 }
416 break;
417 case '?': /* ? or unrecognized option */
418 Usage();
419 return (-1);
420 }
421 }
422
423 if (ArgDebugLevel > 0)
424 (void) fprintf(ArgLogFile,
425 gettext("Processing switch arguments\n"));
426
427 /* re-read switch arguments */
428 optind = 1;
429 while ((option_letter = getopt(argc, argv, options_string)) != EOF) {
430 switch (option_letter) {
431 case 'd':
432 ArgDebugLevel = atoi(optarg);
433 break;
434 case 'e':
435 /* This was handled in earlier pass through args */
436 break;
437 case 'l':
438 ArgNoPageLabels = TRUE;
439 break;
440 case 'r':
441 ArgReverse = TRUE;
442 break;
443 case 's':
444 ArgSeparatorPS = optarg;
445 break;
446 case 'b':
447 ArgBannerPS = optarg;
448 break;
449 case 't':
450 ArgTrailerPS = optarg;
451 break;
452 case 'L':
453 ArgPSLib = optarg;
454 break;
455 case '?': /* ? or unrecognized option */
456 Usage();
457 return (-1);
458 }
459 }
460
461 /* Adjust arguments to skip over options */
462 argc -= optind; /* Number of remaining(non-switch) args */
463 argv += optind; /* argv[0] is first(non-switch) args */
464
465 if (argc != 5) {
466 (void) fprintf(ArgLogFile,
467 gettext("Wrong number of arguments.\n\n"));
468 Usage();
469 return (-1);
470 }
471
472 ArgPrinter = argv++[0];
473 ArgJobID = argv++[0];
474 ArgUser = argv++[0];
475 ArgTitle = argv++[0];
476 ArgFile = argv++[0];
477
478 if (ArgDebugLevel >= 1) {
479 (void) fprintf(ArgLogFile, gettext("Arguments processed\n"));
480 (void) fprintf(ArgLogFile, gettext("Printer: %s\n"),
481 ArgPrinter);
482 (void) fprintf(ArgLogFile, gettext("Job ID: %s\n"), ArgJobID);
483 (void) fprintf(ArgLogFile, gettext("User: %s\n"), ArgUser);
484 (void) fprintf(ArgLogFile, gettext("Title: %s\n"), ArgTitle);
485 (void) fprintf(ArgLogFile, gettext("File: %s\n"), ArgFile);
486 }
487
488 return (0);
489 }
490
491
492 static void
Usage(void)493 Usage(void)
494 {
495 static const char *OPTFMT = " %-8s %-9s %s\n";
496
497 (void) fprintf(ArgLogFile,
498 gettext("Usage: lp.tsol_separator [OPTIONS] %s\n"),
499 gettext("PRINTER JOBID HOST!USER TITLE FILE"));
500 (void) fprintf(ArgLogFile, gettext(" OPTIONS:\n"));
501 (void) fprintf(ArgLogFile, OPTFMT, "-r", gettext("Reverse"),
502 gettext("Reverse banner/trailer order"));
503 (void) fprintf(ArgLogFile, OPTFMT, "-l", gettext("Labels"),
504 gettext("Suppress page header/footer labels"));
505 (void) fprintf(ArgLogFile, OPTFMT, gettext("-b FILE"),
506 gettext("Banner"),
507 gettext("PostScript program for banner (default tsol_banner.ps)"));
508 (void) fprintf(ArgLogFile, OPTFMT, gettext("-s FILE"),
509 gettext("Separator"),
510 gettext("PostScript program for separator "
511 "(default tsol_separator.ps)"));
512 (void) fprintf(ArgLogFile, OPTFMT, gettext("-t FILE"),
513 gettext("Trailer"),
514 gettext("PostScript program for trailer "
515 "(default tsol_trailer.ps)"));
516 (void) fprintf(ArgLogFile, OPTFMT, gettext("-L DIR"),
517 gettext("Library"),
518 gettext("Directory to search for PostScript programs"));
519 (void) fprintf(ArgLogFile, OPTFMT, "", "",
520 gettext("(default /usr/lib/lp/postscript)"));
521 (void) fprintf(ArgLogFile, OPTFMT, gettext("-d N"), gettext("Debug"),
522 gettext("Set debug level to N"));
523 (void) fprintf(ArgLogFile, OPTFMT, gettext("-e FILE"),
524 gettext("Error File"),
525 gettext("Append error and debugging output to FILE"));
526 }
527