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 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 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 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 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 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 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 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 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 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 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 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 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