12264Sjacobs /* 22264Sjacobs * CDDL HEADER START 32264Sjacobs * 42264Sjacobs * The contents of this file are subject to the terms of the 52264Sjacobs * Common Development and Distribution License (the "License"). 62264Sjacobs * You may not use this file except in compliance with the License. 72264Sjacobs * 82264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92264Sjacobs * or http://www.opensolaris.org/os/licensing. 102264Sjacobs * See the License for the specific language governing permissions 112264Sjacobs * and limitations under the License. 122264Sjacobs * 132264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 142264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 162264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 172264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 182264Sjacobs * 192264Sjacobs * CDDL HEADER END 202264Sjacobs */ 212264Sjacobs 222264Sjacobs /* 23*6725Sjacobs * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242264Sjacobs * Use is subject to license terms. 252264Sjacobs * 262264Sjacobs */ 272264Sjacobs 282264Sjacobs /* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */ 292264Sjacobs 302264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 312264Sjacobs 322264Sjacobs #include <stdio.h> 332264Sjacobs #include <stdlib.h> 343125Sjacobs #include <unistd.h> 353125Sjacobs #include <fcntl.h> 362264Sjacobs #include <stdarg.h> 372264Sjacobs #include <string.h> 382264Sjacobs #include <errno.h> 392264Sjacobs #include <syslog.h> 402264Sjacobs #include <libintl.h> 413125Sjacobs #include <pwd.h> 423125Sjacobs #include <grp.h> 433125Sjacobs #include <sys/types.h> 443125Sjacobs #include <sys/stat.h> 453125Sjacobs #include <sys/socket.h> 463125Sjacobs #include <netinet/in.h> 473125Sjacobs #include <arpa/inet.h> 483125Sjacobs #include <netdb.h> 493125Sjacobs #include <sys/systeminfo.h> 502264Sjacobs 512264Sjacobs #include <papi.h> 523125Sjacobs #include <uri.h> 532264Sjacobs #include "common.h" 542264Sjacobs 552264Sjacobs #define ACK(fp) { (void) fputc('\0', fp); (void) fflush(fp); } 562264Sjacobs #define NACK(fp) { (void) fputc('\1', fp); (void) fflush(fp); } 572264Sjacobs 582264Sjacobs /* 592264Sjacobs * This file contains the front-end of the BSD Print Protocol adaptor. This 602264Sjacobs * code assumes a BSD Socket interface to the networking side. 612264Sjacobs */ 622264Sjacobs 633125Sjacobs static char * 643125Sjacobs remote_host_name(FILE *fp) 653125Sjacobs { 663125Sjacobs struct hostent *hp; 673125Sjacobs struct sockaddr_in6 peer; 683125Sjacobs socklen_t peer_len = sizeof (peer); 693125Sjacobs int fd = fileno(fp); 703125Sjacobs int error_num; 713125Sjacobs char myname[MAXHOSTNAMELEN], tmp_buf[INET6_ADDRSTRLEN]; 723125Sjacobs char *hostname; 733125Sjacobs 743125Sjacobs /* who is our peer ? */ 753125Sjacobs if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) { 763125Sjacobs if ((errno != ENOTSOCK) && (errno != EINVAL)) 773125Sjacobs return (NULL); 783125Sjacobs else 793125Sjacobs return (strdup("localhost")); 803125Sjacobs } 813125Sjacobs 823125Sjacobs /* get their name or return a string containing their address */ 833125Sjacobs if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr, 843125Sjacobs sizeof (struct in6_addr), AF_INET6, 853125Sjacobs &error_num)) == NULL) { 863125Sjacobs return (strdup(inet_ntop(peer.sin6_family, 873125Sjacobs &peer.sin6_addr, tmp_buf, sizeof (tmp_buf)))); 883125Sjacobs } 893125Sjacobs 903125Sjacobs /* is it "localhost" ? */ 913125Sjacobs if (strcasecmp(hp->h_name, "localhost") == 0) 923125Sjacobs return (strdup("localhost")); 933125Sjacobs 943125Sjacobs /* duplicate the name because gethostbyXXXX() is not reentrant */ 953125Sjacobs hostname = strdup(hp->h_name); 963125Sjacobs (void) sysinfo(SI_HOSTNAME, myname, sizeof (myname)); 973125Sjacobs 983125Sjacobs /* is it from one of my addresses ? */ 993125Sjacobs if ((hp = getipnodebyname(myname, AF_INET6, AI_ALL|AI_V4MAPPED, 1003125Sjacobs &error_num)) != NULL) { 1013125Sjacobs struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list; 1023125Sjacobs int i = 0; 1033125Sjacobs 1043125Sjacobs while (tmp[i] != NULL) { 1053125Sjacobs if (memcmp(tmp[i++], &peer.sin6_addr, hp->h_length) 1063125Sjacobs == 0) { 1073125Sjacobs free(hostname); 1083125Sjacobs return (strdup("localhost")); 1093125Sjacobs } 1103125Sjacobs } 1113125Sjacobs } 1123125Sjacobs 1133125Sjacobs /* It must be someone else */ 1143125Sjacobs return (hostname); 1153125Sjacobs } 1163125Sjacobs 1173125Sjacobs static void 1182264Sjacobs fatal(FILE *fp, char *fmt, ...) 1192264Sjacobs { 1202264Sjacobs va_list ap; 1212264Sjacobs 1222264Sjacobs va_start(ap, fmt); 1232264Sjacobs vsyslog(LOG_DEBUG, fmt, ap); 1242264Sjacobs vfprintf(fp, fmt, ap); 1252264Sjacobs va_end(ap); 1263125Sjacobs exit(1); 1272264Sjacobs } 1282264Sjacobs 1292264Sjacobs static void 1303125Sjacobs cleanup(char ***files, char **cf) 1313125Sjacobs { 1323125Sjacobs if (*files != NULL) { 1333125Sjacobs int i; 1343125Sjacobs 1353125Sjacobs for (i = 0; (*files)[i] != NULL; i++) { 1363125Sjacobs (void) unlink((*files)[i]); 1373125Sjacobs free((*files)[i]); 1383125Sjacobs } 1393125Sjacobs free(*files); 1403125Sjacobs *files = NULL; 1413125Sjacobs } 1423125Sjacobs 1433125Sjacobs if (*cf != NULL) { 1443125Sjacobs free(*cf); 1453125Sjacobs *cf = NULL; 1463125Sjacobs } 1473125Sjacobs } 1483125Sjacobs 1493125Sjacobs static papi_attribute_t ** 1503125Sjacobs parse_cf(papi_service_t svc, char *cf, char **files) 1512264Sjacobs { 1523125Sjacobs papi_attribute_t **list = NULL; 1533125Sjacobs char previous = NULL, 1543125Sjacobs *entry, 1553125Sjacobs *s, 1563125Sjacobs text[BUFSIZ]; 1573125Sjacobs int count = 0, 1583125Sjacobs copies_set = 0, 1593125Sjacobs copies = 0; 1603125Sjacobs 1613125Sjacobs for (entry = strtok(cf, "\n"); entry != NULL; 1623125Sjacobs entry = strtok(NULL, "\n")) { 1633125Sjacobs char *format = NULL; 1643125Sjacobs 1653125Sjacobs /* count the copies */ 1663125Sjacobs if ((entry[0] >= 'a') && (entry[0] <= 'z') && 1673125Sjacobs (copies_set == 0) && (previous == entry[0])) 1683125Sjacobs copies++; 1693125Sjacobs else if ((previous >= 'a') && (previous <= 'z')) 1703125Sjacobs copies_set = 1; 1713125Sjacobs previous = entry[0]; 1722264Sjacobs 1733125Sjacobs /* process the control message */ 1743125Sjacobs switch (entry[0]) { 1753125Sjacobs /* RFC-1179 options */ 1763125Sjacobs case 'J': /* RFC-1179 Banner Job Name */ 1773125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1783125Sjacobs "job-name", ++entry); 1793125Sjacobs break; 1803125Sjacobs case 'C': /* RFC-1179 Banner Class Name */ 1813125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1823125Sjacobs "rfc-1179-class", ++entry); 1833125Sjacobs break; 1843125Sjacobs case 'L': /* RFC-1179 Banner toggle */ 1853125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1863125Sjacobs "job-sheets", "standard"); 1873125Sjacobs break; 1883125Sjacobs case 'T': /* RFC-1179 Title (pr) */ 1893125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1903125Sjacobs "pr-title", ++entry); 1913125Sjacobs break; 1923125Sjacobs case 'H': /* RFC-1179 Host */ 1933125Sjacobs /* 1943125Sjacobs * use the host as known by us, not by them 1953125Sjacobs * 1963125Sjacobs * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1973125Sjacobs * "job-originating-host-name", ++entry); 1983125Sjacobs */ 1993125Sjacobs break; 2003125Sjacobs case 'P': /* RFC-1179 User */ 2013125Sjacobs ++entry; 2023125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2033125Sjacobs "requesting-user-name", entry); 2043125Sjacobs papiServiceSetUserName(svc, entry); 2053125Sjacobs break; 2063125Sjacobs case 'M': /* RFC-1179 Mail to User */ 2073125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 2083125Sjacobs "rfc-1179-mail", 1); 2093125Sjacobs break; 2103125Sjacobs case 'W': /* RFC-1179 Width (pr) */ 2113125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 2123125Sjacobs "pr-width", atoi(++entry)); 2133125Sjacobs break; 2143125Sjacobs case 'I': /* RFC-1179 Indent (pr) */ 2153125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 2163125Sjacobs "pr-indent", atoi(++entry)); 2173125Sjacobs break; 2183125Sjacobs case 'N': /* RFC-1179 Filename */ 2193125Sjacobs /* could have HPUX extension embedded */ 2203125Sjacobs if (entry[1] != ' ') { /* real pathname */ 2213125Sjacobs #ifdef DEBUG 2223125Sjacobs papiAttributeListAddString(&list, 2233125Sjacobs PAPI_ATTR_EXCL, 2243125Sjacobs "flist", ++entry); 2253125Sjacobs #endif 2263125Sjacobs } else if (entry[2] == 'O') /* HPUX lp -o options */ 2273125Sjacobs papiAttributeListFromString(&list, 2283125Sjacobs PAPI_ATTR_APPEND, ++entry); 2293125Sjacobs break; 2303125Sjacobs case 'U': /* RFC-1179 Unlink */ 2313125Sjacobs break; /* ignored */ 2323125Sjacobs case '1': /* RFC-1179 TROFF Font R */ 2333125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2343125Sjacobs "rfc-1179-font-r", ++entry); 2353125Sjacobs break; 2363125Sjacobs case '2': /* RFC-1179 TROFF Font I */ 2373125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2383125Sjacobs "rfc-1179-font-i", ++entry); 2393125Sjacobs break; 2403125Sjacobs case '3': /* RFC-1179 TROFF Font B */ 2413125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2423125Sjacobs "rfc-1179-font-b", ++entry); 2433125Sjacobs break; 2443125Sjacobs case '4': /* RFC-1179 TROFF Font S */ 2453125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2463125Sjacobs "rfc-1179-font-s", ++entry); 2473125Sjacobs break; 2483125Sjacobs case 'f': /* RFC-1179 ASCII file (print) */ 2493125Sjacobs format = "text/plain"; 2503125Sjacobs if (is_postscript(files[0]) == 1) 2513125Sjacobs format = "application/postscript"; 2523125Sjacobs break; 2533125Sjacobs case 'l': /* RFC-1179 CATV file (print) */ 2543125Sjacobs format = "application/octet-stream"; 2553125Sjacobs if (is_postscript(files[0]) == 1) 2563125Sjacobs format = "application/postscript"; 2573125Sjacobs break; 2583125Sjacobs case 'o': /* RFC-1179 Postscript file (print) */ 2593125Sjacobs format = "application/postscript"; 2603125Sjacobs break; 2613125Sjacobs case 'p': /* RFC-1179 PR file (print) */ 2623125Sjacobs format = "application/x-pr"; 2633125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 2643125Sjacobs "pr-filter", 1); 2653125Sjacobs break; 2663125Sjacobs case 't': /* RFC-1179 TROFF file (print) */ 2673125Sjacobs format = "application/x-troff"; 2683125Sjacobs break; 2693125Sjacobs case 'n': /* RFC-1179 DITROFF file (print) */ 2703125Sjacobs format = "application/x-ditroff"; 2713125Sjacobs break; 2723125Sjacobs case 'd': /* RFC-1179 DVI file (print) */ 2733125Sjacobs format = "application/x-dvi"; 2743125Sjacobs break; 2753125Sjacobs case 'g': /* RFC-1179 GRAPH file (print) */ 2763125Sjacobs format = "application/x-plot"; 2773125Sjacobs break; 2783125Sjacobs case 'c': /* RFC-1179 CIF file (print) */ 2793125Sjacobs format = "application/x-cif"; 2803125Sjacobs break; 2813125Sjacobs case 'v': /* RFC-1179 RASTER file (print) */ 2823125Sjacobs format = "application/x-raster"; 2833125Sjacobs break; 2843125Sjacobs case 'r': /* RFC-1179 FORTRAN file (print) */ 2853125Sjacobs format = "application/x-fortran"; 2863125Sjacobs break; 2873125Sjacobs /* Sun Solaris Extensions */ 2883125Sjacobs case 'O': 2893125Sjacobs ++entry; 2903125Sjacobs do { 2913125Sjacobs if (*entry != '"') 2923125Sjacobs text[count++] = *entry; 2933125Sjacobs } while (*entry++); 2943125Sjacobs papiAttributeListFromString(&list, PAPI_ATTR_APPEND, 2953125Sjacobs text); 2963125Sjacobs break; 2973125Sjacobs case '5': 2983125Sjacobs ++entry; 2993125Sjacobs switch (entry[0]) { 3003125Sjacobs case 'f': /* Solaris form */ 3013125Sjacobs papiAttributeListAddString(&list, 3023125Sjacobs PAPI_ATTR_EXCL, 3033125Sjacobs "form", ++entry); 3043125Sjacobs break; 3053125Sjacobs case 'H': /* Solaris handling */ 3063125Sjacobs ++entry; 3073125Sjacobs if (strcasecmp(entry, "hold") == 0) 3083125Sjacobs papiAttributeListAddString(&list, 3093125Sjacobs PAPI_ATTR_EXCL, 3103125Sjacobs "job-hold-until", "indefinite"); 311*6725Sjacobs else if (strcasecmp(entry, "immediate") == 0) 3123125Sjacobs papiAttributeListAddString(&list, 3133125Sjacobs PAPI_ATTR_EXCL, 3143125Sjacobs "job-hold-until", "no-hold"); 3153125Sjacobs else 3163125Sjacobs papiAttributeListAddString(&list, 3173125Sjacobs PAPI_ATTR_EXCL, 3183125Sjacobs "job-hold-until", entry); 3193125Sjacobs break; 3203125Sjacobs case 'p': /* Solaris notification */ 3213125Sjacobs papiAttributeListAddBoolean(&list, 3223125Sjacobs PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 3233125Sjacobs break; 324*6725Sjacobs case 'P': { /* Solaris page list */ 325*6725Sjacobs char buf[BUFSIZ]; 326*6725Sjacobs 327*6725Sjacobs snprintf(buf, sizeof (buf), "page-ranges=%s", 328*6725Sjacobs ++entry); 329*6725Sjacobs papiAttributeListFromString(&list, 330*6725Sjacobs PAPI_ATTR_EXCL, buf); 331*6725Sjacobs } 3323125Sjacobs break; 3333125Sjacobs case 'q': { /* Solaris priority */ 3343125Sjacobs int i = atoi(optarg); 3353125Sjacobs 336*6725Sjacobs i = 100 - (i * 2.5); 3373125Sjacobs if ((i < 1) || (i > 100)) 3383125Sjacobs i = 50; 3393125Sjacobs papiAttributeListAddInteger(&list, 340*6725Sjacobs PAPI_ATTR_EXCL, "job-priority", i); 3413125Sjacobs } 3423125Sjacobs break; 3433125Sjacobs case 'S': /* Solaris character set */ 3443125Sjacobs papiAttributeListAddString(&list, 3453125Sjacobs PAPI_ATTR_EXCL, "lp-charset", 3463125Sjacobs ++entry); 3473125Sjacobs break; 3483125Sjacobs case 'T': /* Solaris type */ 3493125Sjacobs format = lp_type_to_mime_type(++entry); 3503125Sjacobs break; 3513125Sjacobs case 'y': /* Solaris mode */ 3523125Sjacobs papiAttributeListAddString(&list, 3533125Sjacobs PAPI_ATTR_APPEND, "lp-modes", ++entry); 3543125Sjacobs break; 3553125Sjacobs default: 3563125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3573125Sjacobs "Warning: cf message (%s) ignored", 3583125Sjacobs entry); 3593125Sjacobs break; 3603125Sjacobs } 3613125Sjacobs break; 3623125Sjacobs /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 3633125Sjacobs 3643125Sjacobs default: 3653125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3663125Sjacobs "Warning: cf message (%s) ignored", entry); 3673125Sjacobs break; 3683125Sjacobs } 3693125Sjacobs 3703125Sjacobs if (format != NULL) 3713125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3723125Sjacobs "document-format", format); 3733125Sjacobs } 3743125Sjacobs 3753125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 3763125Sjacobs "copies", ++copies); 3773125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3783125Sjacobs "job-sheets", "none"); 3793125Sjacobs 3803125Sjacobs return (list); 3813125Sjacobs } 3823125Sjacobs 3833125Sjacobs static papi_status_t 3843125Sjacobs submit_job(papi_service_t svc, FILE *ifp, char *printer, char *cf, char **files) 3853125Sjacobs { 3863125Sjacobs papi_attribute_t **list = NULL; 3873125Sjacobs papi_status_t status; 3883125Sjacobs papi_job_t job = NULL; 3893125Sjacobs char *format = ""; 3903125Sjacobs 3913125Sjacobs if ((list = parse_cf(svc, cf, files)) != NULL) { 3923125Sjacobs /* use the host as known by us, not by them */ 3933125Sjacobs char *host = remote_host_name(ifp); 3943125Sjacobs 3953125Sjacobs if (host != NULL) { 3963125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 3973125Sjacobs "job-originating-host-name", host); 3983125Sjacobs free(host); 3993125Sjacobs } 4003125Sjacobs } 4013125Sjacobs 4023125Sjacobs status = papiJobSubmit(svc, printer, list, NULL, files, &job); 4033125Sjacobs syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 4043125Sjacobs if (status != PAPI_OK) { 4053125Sjacobs char *tmp = papiServiceGetStatusMessage(svc); 4063125Sjacobs 4073125Sjacobs syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 4083125Sjacobs } 4093125Sjacobs papiJobFree(job); 4103125Sjacobs 4113125Sjacobs return (status); 4123125Sjacobs } 4133125Sjacobs 4143125Sjacobs static char * 4153125Sjacobs receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 4163125Sjacobs { 4173125Sjacobs char *ptr, *cf_data; 4183125Sjacobs 4193125Sjacobs if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 4203125Sjacobs NACK(ofp); 4213125Sjacobs return (NULL); 4223125Sjacobs } else 4233125Sjacobs ACK(ofp); 4243125Sjacobs 4253125Sjacobs while (size > 0) { 4263125Sjacobs int rc; 4273125Sjacobs 4283125Sjacobs if (((rc = fread(ptr, 1, size, ifp)) == 0) && 4293125Sjacobs (feof(ifp) != 0)) { 4303125Sjacobs free(cf_data); 4313125Sjacobs return (NULL); 4323125Sjacobs } else { 4333125Sjacobs ptr += rc; 4343125Sjacobs size -= rc; 4353125Sjacobs } 4363125Sjacobs } 4373125Sjacobs syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 4383125Sjacobs 4393125Sjacobs if (fgetc(ifp) != 0) { 4403125Sjacobs free(cf_data); 4413125Sjacobs return (NULL); 4423125Sjacobs } 4432264Sjacobs ACK(ofp); 4442264Sjacobs 4453125Sjacobs return (cf_data); 4463125Sjacobs } 4473125Sjacobs 4483125Sjacobs static char * 4493125Sjacobs receive_data_file(FILE *ifp, FILE *ofp, int size) 4503125Sjacobs { 4513125Sjacobs char file[] = "lpdXXXXXX"; 4523125Sjacobs char buf[BUFSIZ]; 4533125Sjacobs int fd; 4543125Sjacobs 4553125Sjacobs if ((fd = mkstemp(file)) < 0) { 4563125Sjacobs NACK(ofp); 4573125Sjacobs return (NULL); 4583125Sjacobs } else 4593125Sjacobs ACK(ofp); 4603125Sjacobs 4613125Sjacobs while (size > 0) { 4623125Sjacobs int rc = ((size > BUFSIZ) ? BUFSIZ : size); 4633125Sjacobs 4643125Sjacobs if (((rc = fread(buf, 1, rc, ifp)) == 0) && 4653125Sjacobs (feof(ifp) != 0)) { 4663125Sjacobs close(fd); 4673125Sjacobs unlink(file); 4683125Sjacobs return (NULL); 4693125Sjacobs } else { 4703125Sjacobs char *ptr = buf; 4713125Sjacobs 4723125Sjacobs while (rc > 0) { 4733125Sjacobs int wrc = write(fd, ptr, rc); 4743125Sjacobs 4753125Sjacobs if (wrc < 0) { 4763125Sjacobs close(fd); 4773125Sjacobs unlink(file); 4783127Sjacobs return (NULL); 4793125Sjacobs } 4803125Sjacobs 4813125Sjacobs ptr += wrc; 4823125Sjacobs size -= wrc; 4833125Sjacobs rc -= wrc; 4843125Sjacobs } 4853125Sjacobs } 4863125Sjacobs } 4873125Sjacobs close(fd); 4883125Sjacobs if (fgetc(ifp) != 0) { 4893125Sjacobs unlink(file); 4903125Sjacobs return (NULL); 4913125Sjacobs } 4923125Sjacobs ACK(ofp); 4933125Sjacobs 4943125Sjacobs return (strdup(file)); 4953125Sjacobs } 4963127Sjacobs 4973125Sjacobs static papi_status_t 4983125Sjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 4993125Sjacobs { 5003125Sjacobs papi_status_t status = PAPI_OK; 5013125Sjacobs char *file, **files = NULL; /* the job data files */ 5023125Sjacobs char *cf = NULL; 5033125Sjacobs char buf[BUFSIZ]; 5043125Sjacobs 5053125Sjacobs while (fgets(buf, sizeof (buf), ifp) != NULL) { 5063125Sjacobs int size; 5073125Sjacobs 5083125Sjacobs syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 5093125Sjacobs #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 5103125Sjacobs if ((buf[0] > '0') && (buf[0] < '4')) 5113125Sjacobs buf[0] -= '0'; 5123125Sjacobs #endif 5133125Sjacobs switch (buf[0]) { 5142264Sjacobs case 0x01: /* Abort */ 5153125Sjacobs cleanup(&files, &cf); 5162264Sjacobs break; 5173125Sjacobs case 0x02: { /* Receive control file */ 5183125Sjacobs cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1])); 5193125Sjacobs if (cf == NULL) { 5203125Sjacobs cleanup(&files, &cf); 5213125Sjacobs return (PAPI_BAD_REQUEST); 5223125Sjacobs } else if (files != NULL) { 5233125Sjacobs status = submit_job(svc, ifp, printer, cf, 5243125Sjacobs files); 5253125Sjacobs cleanup(&files, &cf); 5263125Sjacobs } 5273125Sjacobs } 5282264Sjacobs break; 5292264Sjacobs case 0x03: { /* Receive data file */ 5303125Sjacobs file = receive_data_file(ifp, ofp, atoi(&buf[1])); 5313125Sjacobs if (file == NULL) { 5323125Sjacobs cleanup(&files, &cf); 5333125Sjacobs return (PAPI_TEMPORARY_ERROR); 5343125Sjacobs } 5353125Sjacobs list_append(&files, file); 5362264Sjacobs } 5372264Sjacobs break; 5382264Sjacobs default: 5393125Sjacobs cleanup(&files, &cf); 5402264Sjacobs fatal(ofp, "protocol screwup"); 5412264Sjacobs break; 5422264Sjacobs } 5432264Sjacobs } 5442264Sjacobs 5453125Sjacobs if ((cf != NULL) && (files != NULL)) 5463125Sjacobs status = submit_job(svc, ifp, printer, cf, files); 5473125Sjacobs 5483125Sjacobs cleanup(&files, &cf); 5493125Sjacobs 5503125Sjacobs return (status); 5512264Sjacobs } 5522264Sjacobs 5533125Sjacobs static papi_status_t 5542264Sjacobs berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp, 5552264Sjacobs char *printer) 5562264Sjacobs { 5572264Sjacobs papi_status_t status; 5582264Sjacobs papi_printer_t p = NULL; 5593125Sjacobs char *keys[] = { "printer-is-accepting-jobs", NULL }; 5602264Sjacobs 5612264Sjacobs status = papiPrinterQuery(svc, printer, keys, NULL, &p); 5622264Sjacobs if ((status == PAPI_OK) && (p != NULL)) { 5632264Sjacobs papi_attribute_t **attrs = papiPrinterGetAttributeList(p); 5642264Sjacobs char accepting = PAPI_FALSE; 5652264Sjacobs 5662264Sjacobs papiAttributeListGetBoolean(attrs, NULL, 5673125Sjacobs "printer-is-accepting-jobs", &accepting); 5682264Sjacobs 5693125Sjacobs if (accepting == PAPI_TRUE) { 5703125Sjacobs ACK(ofp); 5713125Sjacobs status = berkeley_receive_files(svc, ifp, ofp, printer); 5723125Sjacobs } else 5732264Sjacobs NACK(ofp); 5742264Sjacobs 5752264Sjacobs papiPrinterFree(p); 5762264Sjacobs } else 5772264Sjacobs NACK(ofp); 5783125Sjacobs 5793125Sjacobs return (status); 5802264Sjacobs } 5812264Sjacobs 5823125Sjacobs static int 5833125Sjacobs cyclical_service_check(char *svc_name) 5843125Sjacobs { 5853125Sjacobs papi_attribute_t **list; 5863125Sjacobs char buf[BUFSIZ]; 5873125Sjacobs uri_t *uri = NULL; 5883125Sjacobs char *s = NULL; 5893125Sjacobs 5903125Sjacobs /* was there a printer? */ 5913125Sjacobs if (svc_name == NULL) 5923125Sjacobs return (0); 5933125Sjacobs 5943125Sjacobs if ((list = getprinterbyname(svc_name, NULL)) == NULL) 5953127Sjacobs return (0); /* if it doesnt' resolve, we will fail later */ 5963125Sjacobs 5973125Sjacobs papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 5983125Sjacobs if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 5993127Sjacobs return (0); /* they don't match */ 6003125Sjacobs 6013125Sjacobs /* is it in uri form? */ 6023125Sjacobs if (uri_from_string(s, &uri) < 0) 6033125Sjacobs return (0); 6043125Sjacobs 6053125Sjacobs if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 6063125Sjacobs uri_free(uri); 6073125Sjacobs return (0); 6083125Sjacobs } 6093125Sjacobs 6103125Sjacobs /* is it in lpd form? */ 6113125Sjacobs if (strcasecmp(uri->scheme, "lpd") != 0) { 6123125Sjacobs uri_free(uri); 6133125Sjacobs return (0); 6143125Sjacobs } 6153125Sjacobs 6163125Sjacobs /* is it the local host? */ 6173125Sjacobs sysinfo(SI_HOSTNAME, buf, sizeof (buf)); 6183125Sjacobs if ((strcasecmp(uri->host, "localhost") != 0) && 6193127Sjacobs (strcasecmp(uri->host, buf) != 0)) { 6203125Sjacobs uri_free(uri); 6213125Sjacobs return (0); 6223125Sjacobs } 6233125Sjacobs 6243125Sjacobs uri_free(uri); 6253125Sjacobs return (1); 6263125Sjacobs } 6273125Sjacobs 6283125Sjacobs 6292264Sjacobs /* 6302264Sjacobs * This is the entry point for this program. The program takes the 6312264Sjacobs * following options: 6322264Sjacobs * (none) 6332264Sjacobs */ 6342264Sjacobs int 6352264Sjacobs main(int ac, char *av[]) 6362264Sjacobs { 6372264Sjacobs papi_status_t status; 6382264Sjacobs papi_service_t svc = NULL; 6392264Sjacobs papi_encryption_t encryption = PAPI_ENCRYPT_NEVER; 6402264Sjacobs FILE *ifp = stdin, 6412264Sjacobs *ofp = stdout; 6422264Sjacobs int c; 6432264Sjacobs char buf[BUFSIZ], 6442264Sjacobs **args, 6453125Sjacobs *printer, 6463125Sjacobs *run_dir = "/var/run/in.lpd", 6473125Sjacobs *run_user = NULL; 6483125Sjacobs struct passwd *pw = NULL; 6492264Sjacobs 6503125Sjacobs (void) chdir("/tmp"); /* run in /tmp by default */ 6512264Sjacobs openlog("bsd-gw", LOG_PID, LOG_LPR); 6522264Sjacobs 6533125Sjacobs while ((c = getopt(ac, av, "Ed:u:")) != EOF) 6542264Sjacobs switch (c) { 6552264Sjacobs case 'E': 6562264Sjacobs encryption = PAPI_ENCRYPT_ALWAYS; 6572264Sjacobs break; 6583125Sjacobs case 'd': /* run where they tell you */ 6593125Sjacobs run_dir = optarg; 6603125Sjacobs break; 6613125Sjacobs case 'u': /* run as */ 6623125Sjacobs run_user = optarg; 6633125Sjacobs break; 6642264Sjacobs default: 6652264Sjacobs ; 6662264Sjacobs } 6672264Sjacobs 6683125Sjacobs if (run_user != NULL) /* get the requested user info */ 6693125Sjacobs pw = getpwnam(run_user); 6703127Sjacobs 6713125Sjacobs if (run_dir != NULL) { /* setup the run_dir */ 6723125Sjacobs (void) mkdir(run_dir, 0700); 6733125Sjacobs if (pw != NULL) 6743125Sjacobs (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 6753125Sjacobs } 6763125Sjacobs 6773125Sjacobs if (pw != NULL) { /* run as the requested user */ 6783127Sjacobs syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 6793125Sjacobs pw->pw_name, pw->pw_uid, pw->pw_gid); 6803125Sjacobs initgroups(pw->pw_name, pw->pw_gid); 6813125Sjacobs setgid(pw->pw_gid); 6823125Sjacobs setuid(pw->pw_uid); 6833125Sjacobs } 6843125Sjacobs 6853125Sjacobs if (run_dir != NULL) /* move to the run_dir */ 6863125Sjacobs if (chdir(run_dir) < 0) { 6873125Sjacobs syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 6883125Sjacobs exit(1); 6893125Sjacobs } 6903125Sjacobs 6913125Sjacobs syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 6923125Sjacobs 6932264Sjacobs if (fgets(buf, sizeof (buf), ifp) == NULL) { 6942264Sjacobs if (feof(ifp) == 0) 6952264Sjacobs syslog(LOG_ERR, "Error reading from connection: %s", 6962264Sjacobs strerror(errno)); 6972264Sjacobs exit(1); 6982264Sjacobs } 6992264Sjacobs 7003125Sjacobs syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 7013125Sjacobs 7023125Sjacobs #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 7033125Sjacobs if ((buf[0] > '0') && (buf[0] < '6')) 7043125Sjacobs buf[0] -= '0'; 7053125Sjacobs #endif 7063125Sjacobs 7072264Sjacobs if ((buf[0] < 1) || (buf[0] > 5)) { 7082264Sjacobs fatal(ofp, "Invalid protocol request (%d): %c%s\n", 7092264Sjacobs buf[0], buf[0], buf); 7102264Sjacobs exit(1); 7112264Sjacobs } 7122264Sjacobs 7132264Sjacobs args = strsplit(&buf[1], "\t\n "); 7142264Sjacobs printer = *args++; 7152264Sjacobs 7162264Sjacobs if (printer == NULL) { 7172264Sjacobs fatal(ofp, "Can't determine requested printer"); 7182264Sjacobs exit(1); 7192264Sjacobs } 7202264Sjacobs 7213125Sjacobs if (cyclical_service_check(printer) != 0) { 7223125Sjacobs fatal(ofp, "%s is cyclical\n", printer); 7233125Sjacobs exit(1); 7243125Sjacobs } 7253125Sjacobs 7262264Sjacobs status = papiServiceCreate(&svc, printer, NULL, NULL, NULL, 7272264Sjacobs encryption, NULL); 7282264Sjacobs if (status != PAPI_OK) { 7292264Sjacobs fatal(ofp, "Failed to contact service for %s: %s\n", printer, 7302264Sjacobs verbose_papi_message(svc, status)); 7312264Sjacobs exit(1); 7322264Sjacobs } 7332264Sjacobs 7343125Sjacobs /* 7353125Sjacobs * Trusted Solaris can't be trusting of intermediaries. Pass 7363125Sjacobs * the socket connection to the print service to retrieve the 7373125Sjacobs * sensativity label off of a multi-level port. 7383125Sjacobs */ 7393125Sjacobs (void) papiServiceSetPeer(svc, fileno(ifp)); 7402264Sjacobs 7412264Sjacobs switch (buf[0]) { 7422264Sjacobs case '\1': /* restart printer */ 7432264Sjacobs ACK(ofp); /* there is no equivalent */ 7442264Sjacobs break; 7452264Sjacobs case '\2': /* transfer job(s) */ 7463125Sjacobs status = berkeley_transfer_files(svc, ifp, ofp, printer); 7472264Sjacobs break; 7482264Sjacobs case '\3': /* show queue (short) */ 7492264Sjacobs case '\4': { /* show queue (long) */ 7502264Sjacobs int count; 7512264Sjacobs 7522264Sjacobs for (count = 0; args[count] != 0; count++); 7532264Sjacobs 7542264Sjacobs berkeley_queue_report(svc, ofp, printer, buf[0], count, args); 7552264Sjacobs } 7562264Sjacobs break; 7572264Sjacobs case '\5': { /* cancel job(s) */ 7583125Sjacobs char *user = *args++; 7593125Sjacobs char *host = remote_host_name(ifp); 7602264Sjacobs int count; 7612264Sjacobs 7623125Sjacobs if (host != NULL) { 7633125Sjacobs char buf[BUFSIZ]; 7643125Sjacobs 7653125Sjacobs snprintf(buf, sizeof (buf), "%s@%s", user, host); 7663125Sjacobs status = papiServiceSetUserName(svc, buf); 7673125Sjacobs } else 7683125Sjacobs status = papiServiceSetUserName(svc, user); 7693125Sjacobs 7702264Sjacobs for (count = 0; args[count] != 0; count++); 7712264Sjacobs 7722264Sjacobs berkeley_cancel_request(svc, ofp, printer, count, args); 7732264Sjacobs } 7742264Sjacobs break; 7752264Sjacobs default: 7762264Sjacobs fatal(ofp, "unsupported protocol request (%c), %s", 7772264Sjacobs buf[0], &buf[1]); 7782264Sjacobs } 7792264Sjacobs 7802264Sjacobs (void) fflush(ofp); 7812264Sjacobs 7822264Sjacobs syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s", 7832264Sjacobs buf[0], printer, papiStatusString(status)); 7843125Sjacobs if (status != PAPI_OK) 7853125Sjacobs syslog(LOG_DEBUG, "detail: %s", 7863125Sjacobs verbose_papi_message(svc, status)); 7872264Sjacobs 7882264Sjacobs papiServiceDestroy(svc); 7892264Sjacobs 7902264Sjacobs return (0); 7912264Sjacobs } 792