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