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