1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1996-2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <libintl.h> 32*0Sstevel@tonic-gate #include <locale.h> 33*0Sstevel@tonic-gate #include <signal.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <unistd.h> 37*0Sstevel@tonic-gate #include <sys/mman.h> 38*0Sstevel@tonic-gate #include <sys/socket.h> 39*0Sstevel@tonic-gate #include <fcntl.h> 40*0Sstevel@tonic-gate #include <syslog.h> 41*0Sstevel@tonic-gate #include "netpr.h" 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate static void usage_exit(); 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate static void pipehandler(int); 46*0Sstevel@tonic-gate char data_file_type = 0; 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate main(int argc, char *argv[]) 49*0Sstevel@tonic-gate { 50*0Sstevel@tonic-gate extern char *optarg; 51*0Sstevel@tonic-gate extern int optind; 52*0Sstevel@tonic-gate int opt; 53*0Sstevel@tonic-gate np_job_t *job_data; 54*0Sstevel@tonic-gate char *destination = NULL; 55*0Sstevel@tonic-gate np_bsdjob_t *bsdjob; 56*0Sstevel@tonic-gate np_tcpjob_t *tcpjob; 57*0Sstevel@tonic-gate int sockfd; 58*0Sstevel@tonic-gate int pr_order = CONTROL_FIRST; 59*0Sstevel@tonic-gate char *vendor_pr_name = NULL; 60*0Sstevel@tonic-gate char *tcp_port = NULL; 61*0Sstevel@tonic-gate size_t filesize; 62*0Sstevel@tonic-gate int fd; 63*0Sstevel@tonic-gate caddr_t pa; 64*0Sstevel@tonic-gate int jobstatus; 65*0Sstevel@tonic-gate int exit_status = 0; 66*0Sstevel@tonic-gate int on = 1; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 70*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 71*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 72*0Sstevel@tonic-gate #endif 73*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate openlog("netpr", LOG_PID, LOG_LPR); 76*0Sstevel@tonic-gate (void) signal(SIGPIPE, pipehandler); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* reduce privileges until needed to open reserved port */ 79*0Sstevel@tonic-gate if (seteuid(getuid())) { 80*0Sstevel@tonic-gate syslog(LOG_DEBUG, "seteuid failed, exiting netpr"); 81*0Sstevel@tonic-gate exit(E_FAILURE); 82*0Sstevel@tonic-gate } 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate if ((job_data = init_job()) == NULL) { 85*0Sstevel@tonic-gate fprintf(stderr, gettext("init_job(): out of memory\n")); 86*0Sstevel@tonic-gate exit(E_RETRY); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate while ((opt = getopt(argc, argv, "f:I:p:d:T:P:t:U:c:b")) != EOF) 90*0Sstevel@tonic-gate switch (opt) { 91*0Sstevel@tonic-gate case 'f': 92*0Sstevel@tonic-gate data_file_type = optarg[0]; 93*0Sstevel@tonic-gate break; 94*0Sstevel@tonic-gate case 'I': /* foo-49 */ 95*0Sstevel@tonic-gate job_data->request_id = alloc_str((char *)optarg); 96*0Sstevel@tonic-gate syslog(LOG_DEBUG, "request_id: %s", 97*0Sstevel@tonic-gate job_data->request_id); 98*0Sstevel@tonic-gate break; 99*0Sstevel@tonic-gate case 'U': /* awe172-126!wendyp */ 100*0Sstevel@tonic-gate job_data->username = alloc_str((char *)optarg); 101*0Sstevel@tonic-gate syslog(LOG_DEBUG, "username: %s", 102*0Sstevel@tonic-gate job_data->username); 103*0Sstevel@tonic-gate break; 104*0Sstevel@tonic-gate case 'p': /* foo */ 105*0Sstevel@tonic-gate job_data->printer = alloc_str((char *)optarg); 106*0Sstevel@tonic-gate syslog(LOG_DEBUG, "printer: %s", 107*0Sstevel@tonic-gate job_data->printer); 108*0Sstevel@tonic-gate break; 109*0Sstevel@tonic-gate case 'd': /* server for printer */ 110*0Sstevel@tonic-gate job_data->dest = alloc_str((char *)optarg); 111*0Sstevel@tonic-gate syslog(LOG_DEBUG, "dest: %s", 112*0Sstevel@tonic-gate job_data->dest); 113*0Sstevel@tonic-gate break; 114*0Sstevel@tonic-gate case 'T': /* /tmp/file2 */ 115*0Sstevel@tonic-gate job_data->title = alloc_str((char *)optarg); 116*0Sstevel@tonic-gate syslog(LOG_DEBUG, "title: %s", 117*0Sstevel@tonic-gate job_data->title); 118*0Sstevel@tonic-gate break; 119*0Sstevel@tonic-gate case 'P': 120*0Sstevel@tonic-gate if ((strcmp(optarg, "bsd")) == 0) 121*0Sstevel@tonic-gate job_data->protocol = BSD; 122*0Sstevel@tonic-gate else if ((strcmp(optarg, "tcp")) == 0) 123*0Sstevel@tonic-gate job_data->protocol = TCP; 124*0Sstevel@tonic-gate else 125*0Sstevel@tonic-gate usage_exit(); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate syslog(LOG_DEBUG, "protocol: %d", 128*0Sstevel@tonic-gate job_data->protocol); 129*0Sstevel@tonic-gate break; 130*0Sstevel@tonic-gate case 't': 131*0Sstevel@tonic-gate job_data->timeout = atoi(optarg); 132*0Sstevel@tonic-gate if (job_data->timeout < 0) 133*0Sstevel@tonic-gate usage_exit(); 134*0Sstevel@tonic-gate break; 135*0Sstevel@tonic-gate case 'c': 136*0Sstevel@tonic-gate if ((strcmp(optarg, "first")) == 0) 137*0Sstevel@tonic-gate pr_order = CONTROL_FIRST; 138*0Sstevel@tonic-gate else if ((strcmp(optarg, "last")) == 0) 139*0Sstevel@tonic-gate pr_order = DATA_FIRST; 140*0Sstevel@tonic-gate else 141*0Sstevel@tonic-gate usage_exit(); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate syslog(LOG_DEBUG, "bsd print order: %d", pr_order); 144*0Sstevel@tonic-gate break; 145*0Sstevel@tonic-gate case 'b': 146*0Sstevel@tonic-gate job_data->banner = NOBANNER; 147*0Sstevel@tonic-gate syslog(LOG_DEBUG, "banner : %d", 148*0Sstevel@tonic-gate job_data->banner); 149*0Sstevel@tonic-gate break; 150*0Sstevel@tonic-gate case '?': 151*0Sstevel@tonic-gate usage_exit(); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate if ((job_data->dest == NULL) || (job_data->request_id == NULL) || 156*0Sstevel@tonic-gate (job_data->printer == NULL) || (job_data->username == NULL)) 157*0Sstevel@tonic-gate usage_exit(); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Check that there is a file 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if (optind == argc) { 163*0Sstevel@tonic-gate usage_exit(); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate job_data->filename = alloc_str(argv[optind]); 167*0Sstevel@tonic-gate syslog(LOG_DEBUG, "filename : %s", job_data->filename); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate * Sanity check the file 172*0Sstevel@tonic-gate * returns filesize 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if ((filesize = check_file(job_data->filename)) == -1) { 176*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Skipping file %s", 177*0Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate switch (errno) { 180*0Sstevel@tonic-gate case EISDIR: 181*0Sstevel@tonic-gate (void) fprintf(stderr, 182*0Sstevel@tonic-gate gettext("Netpr: %s: Not a regular file\n"), 183*0Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 184*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Not a regular file"); 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate case ESRCH: 187*0Sstevel@tonic-gate (void) fprintf(stderr, 188*0Sstevel@tonic-gate gettext("Netpr: %s: Empty file\n"), 189*0Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 190*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Empty file"); 191*0Sstevel@tonic-gate break; 192*0Sstevel@tonic-gate default: 193*0Sstevel@tonic-gate perror(job_data->filename); 194*0Sstevel@tonic-gate (void) fprintf(stderr, 195*0Sstevel@tonic-gate gettext("Netpr: Cannot access file %s\n"), 196*0Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 197*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot access file."); 198*0Sstevel@tonic-gate break; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * This file not valid, so bail 204*0Sstevel@tonic-gate * Exit with zero so system will keep printing 205*0Sstevel@tonic-gate */ 206*0Sstevel@tonic-gate exit(0); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * file looks ok, open and mmap it 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate if ((fd = open(job_data->filename, O_RDONLY)) < 0) { 213*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Netpr: Cannot open file %s\n"), 214*0Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Error: NULL file")); 215*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot open file: %s", 216*0Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 217*0Sstevel@tonic-gate exit(E_BAD_FILE); 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate if ((pa = mmap((caddr_t)0, filesize, PROT_READ, 221*0Sstevel@tonic-gate (MAP_SHARED | MAP_NORESERVE), fd, (off_t)0)) == MAP_FAILED) { 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate (void) close(fd); 224*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Netpr: Cannot mmap file %s"), 225*0Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Error: NULL file")); 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot mmap file: %s", 228*0Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate exit(E_RETRY); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate if (job_data->protocol == BSD) { 235*0Sstevel@tonic-gate bsdjob = (np_bsdjob_t *) 236*0Sstevel@tonic-gate create_bsd_job(job_data, pr_order, filesize); 237*0Sstevel@tonic-gate if (bsdjob == NULL) 238*0Sstevel@tonic-gate exit(E_FAILURE); 239*0Sstevel@tonic-gate } else { 240*0Sstevel@tonic-gate tcpjob = (np_tcpjob_t *)create_tcp_job(job_data, filesize); 241*0Sstevel@tonic-gate if (tcpjob == NULL) 242*0Sstevel@tonic-gate exit(E_FAILURE); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * Parse destination 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if ((strpbrk(job_data->dest, DEST_SEP)) != NULL) { 250*0Sstevel@tonic-gate if (job_data->protocol == BSD) { 251*0Sstevel@tonic-gate parse_dest(job_data->dest, &destination, 252*0Sstevel@tonic-gate &vendor_pr_name, DEST_SEP); 253*0Sstevel@tonic-gate if (vendor_pr_name != NULL) { 254*0Sstevel@tonic-gate bsdjob->np_printer = vendor_pr_name; 255*0Sstevel@tonic-gate syslog(LOG_DEBUG, "bsd vendor name: %s", 256*0Sstevel@tonic-gate bsdjob->np_printer); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate } else { 259*0Sstevel@tonic-gate parse_dest(job_data->dest, &destination, &tcp_port, 260*0Sstevel@tonic-gate DEST_SEP); 261*0Sstevel@tonic-gate if (tcp_port != NULL) 262*0Sstevel@tonic-gate tcpjob->np_port = tcp_port; 263*0Sstevel@tonic-gate syslog(LOG_DEBUG, "tcp_port %s", 264*0Sstevel@tonic-gate tcpjob->np_port); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate if (destination == NULL || 267*0Sstevel@tonic-gate (job_data->protocol == TCP && tcp_port == NULL)) { 268*0Sstevel@tonic-gate (void) fprintf(stderr, 269*0Sstevel@tonic-gate gettext("Netpr: system error parsing destination %s\n"), 270*0Sstevel@tonic-gate job_data->dest); 271*0Sstevel@tonic-gate syslog(LOG_DEBUG, "system error parsing destination %s", 272*0Sstevel@tonic-gate job_data->dest); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate exit(E_FAILURE); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate } else { 278*0Sstevel@tonic-gate destination = job_data->dest; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate syslog(LOG_DEBUG, "destination : %s", destination); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * We are now ready to open a connection to the printer 284*0Sstevel@tonic-gate * and print each of the files 285*0Sstevel@tonic-gate */ 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if (job_data->protocol == BSD) { 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* set privileges to get reserved port */ 290*0Sstevel@tonic-gate if (seteuid(0)) { 291*0Sstevel@tonic-gate syslog(LOG_DEBUG, "seteuid(0) failed, exiting netpr"); 292*0Sstevel@tonic-gate exit(E_FAILURE); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate if ((sockfd = net_open(destination, 20)) < 0) { 295*0Sstevel@tonic-gate (void) fprintf(stderr, 296*0Sstevel@tonic-gate gettext("Netpr: Cannot open connection to <%s>\n"), 297*0Sstevel@tonic-gate destination); 298*0Sstevel@tonic-gate syslog(LOG_DEBUG, 299*0Sstevel@tonic-gate "Cannot open connection to %s: retrying", 300*0Sstevel@tonic-gate destination); 301*0Sstevel@tonic-gate exit(E_RETRY); 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate } else { 304*0Sstevel@tonic-gate if ((sockfd = tcp_open(destination, tcpjob, 20)) == -1) { 305*0Sstevel@tonic-gate exit(E_RETRY); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* lower privileges as we now have the reserved port */ 310*0Sstevel@tonic-gate if (setuid(getuid())) { 311*0Sstevel@tonic-gate syslog(LOG_DEBUG, "setuid() failed, exiting netpr"); 312*0Sstevel@tonic-gate exit(E_FAILURE); 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* Set SO_KEEPALIVE on socket to keep open */ 317*0Sstevel@tonic-gate if ((setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 318*0Sstevel@tonic-gate (char *)&on, sizeof (on))) < 0) { 319*0Sstevel@tonic-gate syslog(LOG_DEBUG, "setsocket (SO_KEEPALIVE): %m"); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate if (job_data->protocol == BSD) { 323*0Sstevel@tonic-gate if ((jobstatus = bsd_print(sockfd, pa, bsdjob)) != 0) { 324*0Sstevel@tonic-gate (void) fprintf(stderr, 325*0Sstevel@tonic-gate gettext("Netpr: Error return from bsd_print <%d>\n"), 326*0Sstevel@tonic-gate jobstatus); 327*0Sstevel@tonic-gate syslog(LOG_DEBUG, 328*0Sstevel@tonic-gate "Error return from bsd_print <%d>", jobstatus); 329*0Sstevel@tonic-gate exit_status = E_RETRY; 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate } else { 332*0Sstevel@tonic-gate if ((jobstatus = 333*0Sstevel@tonic-gate tcp_print(sockfd, pa, tcpjob)) != 0) { 334*0Sstevel@tonic-gate (void) fprintf(stderr, 335*0Sstevel@tonic-gate gettext("Netpr: Error return from tcp_print <%d>\n"), 336*0Sstevel@tonic-gate jobstatus); 337*0Sstevel@tonic-gate syslog(LOG_DEBUG, 338*0Sstevel@tonic-gate "Error return from tcp_print <%d>", jobstatus); 339*0Sstevel@tonic-gate exit_status = E_RETRY; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate (void) close(fd); 344*0Sstevel@tonic-gate (void) close(sockfd); 345*0Sstevel@tonic-gate (void) munmap(pa, filesize); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate syslog(LOG_DEBUG, "exit status: %d", exit_status); 348*0Sstevel@tonic-gate return (exit_status); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate static void 352*0Sstevel@tonic-gate usage_exit() 353*0Sstevel@tonic-gate { 354*0Sstevel@tonic-gate (void) fprintf(stderr, 355*0Sstevel@tonic-gate gettext("Usage: netpr -I request_id -p printer -d destination\n")); 356*0Sstevel@tonic-gate (void) fprintf(stderr, 357*0Sstevel@tonic-gate gettext("\t\t-U username [ -f type ] [ -T title ] [ -P protocol ]\n")); 358*0Sstevel@tonic-gate (void) fprintf(stderr, 359*0Sstevel@tonic-gate gettext("\t\t[-t timeout] [ -c ] [ -b ]\n")); 360*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t\tfiles\n")); 361*0Sstevel@tonic-gate exit(E_BAD_INPUT); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate /*ARGSUSED*/ 365*0Sstevel@tonic-gate void 366*0Sstevel@tonic-gate pipehandler(int i) 367*0Sstevel@tonic-gate { 368*0Sstevel@tonic-gate (void) signal(SIGPIPE, pipehandler); 369*0Sstevel@tonic-gate syslog(LOG_DEBUG, "Received SIGPIPE, connection to printer broken"); 370*0Sstevel@tonic-gate exit(E_SIGPIPE); 371*0Sstevel@tonic-gate } 372