10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*320Sceastha * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <libintl.h> 320Sstevel@tonic-gate #include <locale.h> 330Sstevel@tonic-gate #include <signal.h> 340Sstevel@tonic-gate #include <errno.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate #include <sys/mman.h> 380Sstevel@tonic-gate #include <sys/socket.h> 390Sstevel@tonic-gate #include <fcntl.h> 400Sstevel@tonic-gate #include <syslog.h> 410Sstevel@tonic-gate #include "netpr.h" 420Sstevel@tonic-gate 430Sstevel@tonic-gate static void usage_exit(); 440Sstevel@tonic-gate 450Sstevel@tonic-gate static void pipehandler(int); 460Sstevel@tonic-gate char data_file_type = 0; 470Sstevel@tonic-gate 48*320Sceastha int 490Sstevel@tonic-gate main(int argc, char *argv[]) 500Sstevel@tonic-gate { 510Sstevel@tonic-gate extern char *optarg; 520Sstevel@tonic-gate extern int optind; 530Sstevel@tonic-gate int opt; 540Sstevel@tonic-gate np_job_t *job_data; 550Sstevel@tonic-gate char *destination = NULL; 560Sstevel@tonic-gate np_bsdjob_t *bsdjob; 570Sstevel@tonic-gate np_tcpjob_t *tcpjob; 580Sstevel@tonic-gate int sockfd; 590Sstevel@tonic-gate int pr_order = CONTROL_FIRST; 600Sstevel@tonic-gate char *vendor_pr_name = NULL; 610Sstevel@tonic-gate char *tcp_port = NULL; 620Sstevel@tonic-gate size_t filesize; 630Sstevel@tonic-gate int fd; 640Sstevel@tonic-gate caddr_t pa; 650Sstevel@tonic-gate int jobstatus; 660Sstevel@tonic-gate int exit_status = 0; 670Sstevel@tonic-gate int on = 1; 680Sstevel@tonic-gate 690Sstevel@tonic-gate 700Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 710Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 720Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 730Sstevel@tonic-gate #endif 740Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 750Sstevel@tonic-gate 760Sstevel@tonic-gate openlog("netpr", LOG_PID, LOG_LPR); 770Sstevel@tonic-gate (void) signal(SIGPIPE, pipehandler); 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* reduce privileges until needed to open reserved port */ 800Sstevel@tonic-gate if (seteuid(getuid())) { 810Sstevel@tonic-gate syslog(LOG_DEBUG, "seteuid failed, exiting netpr"); 820Sstevel@tonic-gate exit(E_FAILURE); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate 850Sstevel@tonic-gate if ((job_data = init_job()) == NULL) { 860Sstevel@tonic-gate fprintf(stderr, gettext("init_job(): out of memory\n")); 870Sstevel@tonic-gate exit(E_RETRY); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate while ((opt = getopt(argc, argv, "f:I:p:d:T:P:t:U:c:b")) != EOF) 910Sstevel@tonic-gate switch (opt) { 920Sstevel@tonic-gate case 'f': 930Sstevel@tonic-gate data_file_type = optarg[0]; 940Sstevel@tonic-gate break; 950Sstevel@tonic-gate case 'I': /* foo-49 */ 960Sstevel@tonic-gate job_data->request_id = alloc_str((char *)optarg); 970Sstevel@tonic-gate syslog(LOG_DEBUG, "request_id: %s", 980Sstevel@tonic-gate job_data->request_id); 990Sstevel@tonic-gate break; 1000Sstevel@tonic-gate case 'U': /* awe172-126!wendyp */ 1010Sstevel@tonic-gate job_data->username = alloc_str((char *)optarg); 1020Sstevel@tonic-gate syslog(LOG_DEBUG, "username: %s", 1030Sstevel@tonic-gate job_data->username); 1040Sstevel@tonic-gate break; 1050Sstevel@tonic-gate case 'p': /* foo */ 1060Sstevel@tonic-gate job_data->printer = alloc_str((char *)optarg); 1070Sstevel@tonic-gate syslog(LOG_DEBUG, "printer: %s", 1080Sstevel@tonic-gate job_data->printer); 1090Sstevel@tonic-gate break; 1100Sstevel@tonic-gate case 'd': /* server for printer */ 1110Sstevel@tonic-gate job_data->dest = alloc_str((char *)optarg); 1120Sstevel@tonic-gate syslog(LOG_DEBUG, "dest: %s", 1130Sstevel@tonic-gate job_data->dest); 1140Sstevel@tonic-gate break; 1150Sstevel@tonic-gate case 'T': /* /tmp/file2 */ 1160Sstevel@tonic-gate job_data->title = alloc_str((char *)optarg); 1170Sstevel@tonic-gate syslog(LOG_DEBUG, "title: %s", 1180Sstevel@tonic-gate job_data->title); 1190Sstevel@tonic-gate break; 1200Sstevel@tonic-gate case 'P': 1210Sstevel@tonic-gate if ((strcmp(optarg, "bsd")) == 0) 1220Sstevel@tonic-gate job_data->protocol = BSD; 1230Sstevel@tonic-gate else if ((strcmp(optarg, "tcp")) == 0) 1240Sstevel@tonic-gate job_data->protocol = TCP; 1250Sstevel@tonic-gate else 1260Sstevel@tonic-gate usage_exit(); 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate syslog(LOG_DEBUG, "protocol: %d", 1290Sstevel@tonic-gate job_data->protocol); 1300Sstevel@tonic-gate break; 1310Sstevel@tonic-gate case 't': 1320Sstevel@tonic-gate job_data->timeout = atoi(optarg); 1330Sstevel@tonic-gate if (job_data->timeout < 0) 1340Sstevel@tonic-gate usage_exit(); 1350Sstevel@tonic-gate break; 1360Sstevel@tonic-gate case 'c': 1370Sstevel@tonic-gate if ((strcmp(optarg, "first")) == 0) 1380Sstevel@tonic-gate pr_order = CONTROL_FIRST; 1390Sstevel@tonic-gate else if ((strcmp(optarg, "last")) == 0) 1400Sstevel@tonic-gate pr_order = DATA_FIRST; 1410Sstevel@tonic-gate else 1420Sstevel@tonic-gate usage_exit(); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate syslog(LOG_DEBUG, "bsd print order: %d", pr_order); 1450Sstevel@tonic-gate break; 1460Sstevel@tonic-gate case 'b': 1470Sstevel@tonic-gate job_data->banner = NOBANNER; 1480Sstevel@tonic-gate syslog(LOG_DEBUG, "banner : %d", 1490Sstevel@tonic-gate job_data->banner); 1500Sstevel@tonic-gate break; 1510Sstevel@tonic-gate case '?': 1520Sstevel@tonic-gate usage_exit(); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate if ((job_data->dest == NULL) || (job_data->request_id == NULL) || 1570Sstevel@tonic-gate (job_data->printer == NULL) || (job_data->username == NULL)) 1580Sstevel@tonic-gate usage_exit(); 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * Check that there is a file 1620Sstevel@tonic-gate */ 1630Sstevel@tonic-gate if (optind == argc) { 1640Sstevel@tonic-gate usage_exit(); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate job_data->filename = alloc_str(argv[optind]); 1680Sstevel@tonic-gate syslog(LOG_DEBUG, "filename : %s", job_data->filename); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * Sanity check the file 1730Sstevel@tonic-gate * returns filesize 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if ((filesize = check_file(job_data->filename)) == -1) { 1770Sstevel@tonic-gate syslog(LOG_DEBUG, "Skipping file %s", 1780Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate switch (errno) { 1810Sstevel@tonic-gate case EISDIR: 1820Sstevel@tonic-gate (void) fprintf(stderr, 1830Sstevel@tonic-gate gettext("Netpr: %s: Not a regular file\n"), 1840Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 1850Sstevel@tonic-gate syslog(LOG_DEBUG, "Not a regular file"); 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate case ESRCH: 1880Sstevel@tonic-gate (void) fprintf(stderr, 1890Sstevel@tonic-gate gettext("Netpr: %s: Empty file\n"), 1900Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 1910Sstevel@tonic-gate syslog(LOG_DEBUG, "Empty file"); 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate default: 1940Sstevel@tonic-gate perror(job_data->filename); 1950Sstevel@tonic-gate (void) fprintf(stderr, 1960Sstevel@tonic-gate gettext("Netpr: Cannot access file %s\n"), 1970Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Noname")); 1980Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot access file."); 1990Sstevel@tonic-gate break; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * This file not valid, so bail 2050Sstevel@tonic-gate * Exit with zero so system will keep printing 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate exit(0); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * file looks ok, open and mmap it 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate if ((fd = open(job_data->filename, O_RDONLY)) < 0) { 2140Sstevel@tonic-gate (void) fprintf(stderr, gettext("Netpr: Cannot open file %s\n"), 2150Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Error: NULL file")); 2160Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot open file: %s", 2170Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 2180Sstevel@tonic-gate exit(E_BAD_FILE); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if ((pa = mmap((caddr_t)0, filesize, PROT_READ, 2220Sstevel@tonic-gate (MAP_SHARED | MAP_NORESERVE), fd, (off_t)0)) == MAP_FAILED) { 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate (void) close(fd); 2250Sstevel@tonic-gate (void) fprintf(stderr, gettext("Netpr: Cannot mmap file %s"), 2260Sstevel@tonic-gate (job_data->filename ? job_data->filename : "Error: NULL file")); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate syslog(LOG_DEBUG, "Cannot mmap file: %s", 2290Sstevel@tonic-gate job_data->filename ? job_data->filename : "Error NULL file"); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate exit(E_RETRY); 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (job_data->protocol == BSD) { 2360Sstevel@tonic-gate bsdjob = (np_bsdjob_t *) 2370Sstevel@tonic-gate create_bsd_job(job_data, pr_order, filesize); 2380Sstevel@tonic-gate if (bsdjob == NULL) 2390Sstevel@tonic-gate exit(E_FAILURE); 2400Sstevel@tonic-gate } else { 2410Sstevel@tonic-gate tcpjob = (np_tcpjob_t *)create_tcp_job(job_data, filesize); 2420Sstevel@tonic-gate if (tcpjob == NULL) 2430Sstevel@tonic-gate exit(E_FAILURE); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Parse destination 2480Sstevel@tonic-gate */ 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate if ((strpbrk(job_data->dest, DEST_SEP)) != NULL) { 2510Sstevel@tonic-gate if (job_data->protocol == BSD) { 2520Sstevel@tonic-gate parse_dest(job_data->dest, &destination, 2530Sstevel@tonic-gate &vendor_pr_name, DEST_SEP); 2540Sstevel@tonic-gate if (vendor_pr_name != NULL) { 2550Sstevel@tonic-gate bsdjob->np_printer = vendor_pr_name; 2560Sstevel@tonic-gate syslog(LOG_DEBUG, "bsd vendor name: %s", 2570Sstevel@tonic-gate bsdjob->np_printer); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate } else { 2600Sstevel@tonic-gate parse_dest(job_data->dest, &destination, &tcp_port, 2610Sstevel@tonic-gate DEST_SEP); 2620Sstevel@tonic-gate if (tcp_port != NULL) 2630Sstevel@tonic-gate tcpjob->np_port = tcp_port; 2640Sstevel@tonic-gate syslog(LOG_DEBUG, "tcp_port %s", 2650Sstevel@tonic-gate tcpjob->np_port); 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate if (destination == NULL || 2680Sstevel@tonic-gate (job_data->protocol == TCP && tcp_port == NULL)) { 2690Sstevel@tonic-gate (void) fprintf(stderr, 2700Sstevel@tonic-gate gettext("Netpr: system error parsing destination %s\n"), 2710Sstevel@tonic-gate job_data->dest); 2720Sstevel@tonic-gate syslog(LOG_DEBUG, "system error parsing destination %s", 2730Sstevel@tonic-gate job_data->dest); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate exit(E_FAILURE); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate } else { 2790Sstevel@tonic-gate destination = job_data->dest; 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate syslog(LOG_DEBUG, "destination : %s", destination); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate /* 2840Sstevel@tonic-gate * We are now ready to open a connection to the printer 2850Sstevel@tonic-gate * and print each of the files 2860Sstevel@tonic-gate */ 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate if (job_data->protocol == BSD) { 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* set privileges to get reserved port */ 2910Sstevel@tonic-gate if (seteuid(0)) { 2920Sstevel@tonic-gate syslog(LOG_DEBUG, "seteuid(0) failed, exiting netpr"); 2930Sstevel@tonic-gate exit(E_FAILURE); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate if ((sockfd = net_open(destination, 20)) < 0) { 2960Sstevel@tonic-gate (void) fprintf(stderr, 2970Sstevel@tonic-gate gettext("Netpr: Cannot open connection to <%s>\n"), 2980Sstevel@tonic-gate destination); 2990Sstevel@tonic-gate syslog(LOG_DEBUG, 3000Sstevel@tonic-gate "Cannot open connection to %s: retrying", 3010Sstevel@tonic-gate destination); 3020Sstevel@tonic-gate exit(E_RETRY); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } else { 3050Sstevel@tonic-gate if ((sockfd = tcp_open(destination, tcpjob, 20)) == -1) { 3060Sstevel@tonic-gate exit(E_RETRY); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* lower privileges as we now have the reserved port */ 3110Sstevel@tonic-gate if (setuid(getuid())) { 3120Sstevel@tonic-gate syslog(LOG_DEBUG, "setuid() failed, exiting netpr"); 3130Sstevel@tonic-gate exit(E_FAILURE); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* Set SO_KEEPALIVE on socket to keep open */ 3180Sstevel@tonic-gate if ((setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 3190Sstevel@tonic-gate (char *)&on, sizeof (on))) < 0) { 3200Sstevel@tonic-gate syslog(LOG_DEBUG, "setsocket (SO_KEEPALIVE): %m"); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (job_data->protocol == BSD) { 3240Sstevel@tonic-gate if ((jobstatus = bsd_print(sockfd, pa, bsdjob)) != 0) { 3250Sstevel@tonic-gate (void) fprintf(stderr, 3260Sstevel@tonic-gate gettext("Netpr: Error return from bsd_print <%d>\n"), 3270Sstevel@tonic-gate jobstatus); 3280Sstevel@tonic-gate syslog(LOG_DEBUG, 3290Sstevel@tonic-gate "Error return from bsd_print <%d>", jobstatus); 3300Sstevel@tonic-gate exit_status = E_RETRY; 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate } else { 3330Sstevel@tonic-gate if ((jobstatus = 3340Sstevel@tonic-gate tcp_print(sockfd, pa, tcpjob)) != 0) { 3350Sstevel@tonic-gate (void) fprintf(stderr, 3360Sstevel@tonic-gate gettext("Netpr: Error return from tcp_print <%d>\n"), 3370Sstevel@tonic-gate jobstatus); 3380Sstevel@tonic-gate syslog(LOG_DEBUG, 3390Sstevel@tonic-gate "Error return from tcp_print <%d>", jobstatus); 3400Sstevel@tonic-gate exit_status = E_RETRY; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate (void) close(fd); 3450Sstevel@tonic-gate (void) close(sockfd); 3460Sstevel@tonic-gate (void) munmap(pa, filesize); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate syslog(LOG_DEBUG, "exit status: %d", exit_status); 3490Sstevel@tonic-gate return (exit_status); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate static void 3530Sstevel@tonic-gate usage_exit() 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate (void) fprintf(stderr, 3560Sstevel@tonic-gate gettext("Usage: netpr -I request_id -p printer -d destination\n")); 3570Sstevel@tonic-gate (void) fprintf(stderr, 3580Sstevel@tonic-gate gettext("\t\t-U username [ -f type ] [ -T title ] [ -P protocol ]\n")); 3590Sstevel@tonic-gate (void) fprintf(stderr, 3600Sstevel@tonic-gate gettext("\t\t[-t timeout] [ -c ] [ -b ]\n")); 3610Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t\tfiles\n")); 3620Sstevel@tonic-gate exit(E_BAD_INPUT); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /*ARGSUSED*/ 3660Sstevel@tonic-gate void 3670Sstevel@tonic-gate pipehandler(int i) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate (void) signal(SIGPIPE, pipehandler); 3700Sstevel@tonic-gate syslog(LOG_DEBUG, "Received SIGPIPE, connection to printer broken"); 3710Sstevel@tonic-gate exit(E_SIGPIPE); 3720Sstevel@tonic-gate } 373