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