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