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 /* 236725Sjacobs * 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> 386817Sjacobs #include <ctype.h> 392264Sjacobs #include <errno.h> 402264Sjacobs #include <syslog.h> 412264Sjacobs #include <libintl.h> 423125Sjacobs #include <pwd.h> 433125Sjacobs #include <grp.h> 443125Sjacobs #include <sys/types.h> 453125Sjacobs #include <sys/stat.h> 463125Sjacobs #include <sys/socket.h> 473125Sjacobs #include <netinet/in.h> 483125Sjacobs #include <arpa/inet.h> 493125Sjacobs #include <netdb.h> 503125Sjacobs #include <sys/systeminfo.h> 512264Sjacobs 522264Sjacobs #include <papi.h> 533125Sjacobs #include <uri.h> 542264Sjacobs #include "common.h" 552264Sjacobs 562264Sjacobs #define ACK(fp) { (void) fputc('\0', fp); (void) fflush(fp); } 572264Sjacobs #define NACK(fp) { (void) fputc('\1', fp); (void) fflush(fp); } 582264Sjacobs 592264Sjacobs /* 602264Sjacobs * This file contains the front-end of the BSD Print Protocol adaptor. This 612264Sjacobs * code assumes a BSD Socket interface to the networking side. 622264Sjacobs */ 632264Sjacobs 643125Sjacobs static char * 653125Sjacobs remote_host_name(FILE *fp) 663125Sjacobs { 673125Sjacobs struct hostent *hp; 683125Sjacobs struct sockaddr_in6 peer; 693125Sjacobs socklen_t peer_len = sizeof (peer); 703125Sjacobs int fd = fileno(fp); 713125Sjacobs int error_num; 72*7132Sps29005 char tmp_buf[INET6_ADDRSTRLEN]; 733125Sjacobs char *hostname; 743125Sjacobs 753125Sjacobs /* who is our peer ? */ 763125Sjacobs if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) { 773125Sjacobs if ((errno != ENOTSOCK) && (errno != EINVAL)) 783125Sjacobs return (NULL); 793125Sjacobs else 803125Sjacobs return (strdup("localhost")); 813125Sjacobs } 823125Sjacobs 833125Sjacobs /* get their name or return a string containing their address */ 843125Sjacobs if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr, 853125Sjacobs sizeof (struct in6_addr), AF_INET6, 863125Sjacobs &error_num)) == NULL) { 873125Sjacobs return (strdup(inet_ntop(peer.sin6_family, 883125Sjacobs &peer.sin6_addr, tmp_buf, sizeof (tmp_buf)))); 893125Sjacobs } 903125Sjacobs 91*7132Sps29005 hostname = strdup(hp->h_name); 92*7132Sps29005 if (is_localhost(hp->h_name) != 0) 933125Sjacobs return (strdup("localhost")); 943125Sjacobs 953125Sjacobs /* It must be someone else */ 963125Sjacobs return (hostname); 973125Sjacobs } 983125Sjacobs 993125Sjacobs static void 1002264Sjacobs fatal(FILE *fp, char *fmt, ...) 1012264Sjacobs { 1022264Sjacobs va_list ap; 1032264Sjacobs 1042264Sjacobs va_start(ap, fmt); 1052264Sjacobs vsyslog(LOG_DEBUG, fmt, ap); 1062264Sjacobs vfprintf(fp, fmt, ap); 1072264Sjacobs va_end(ap); 1083125Sjacobs exit(1); 1092264Sjacobs } 1102264Sjacobs 1112264Sjacobs static void 1123125Sjacobs cleanup(char ***files, char **cf) 1133125Sjacobs { 1143125Sjacobs if (*files != NULL) { 1153125Sjacobs int i; 1163125Sjacobs 1173125Sjacobs for (i = 0; (*files)[i] != NULL; i++) { 1183125Sjacobs (void) unlink((*files)[i]); 1193125Sjacobs free((*files)[i]); 1203125Sjacobs } 1213125Sjacobs free(*files); 1223125Sjacobs *files = NULL; 1233125Sjacobs } 1243125Sjacobs 1253125Sjacobs if (*cf != NULL) { 1263125Sjacobs free(*cf); 1273125Sjacobs *cf = NULL; 1283125Sjacobs } 1293125Sjacobs } 1303125Sjacobs 1313125Sjacobs static papi_attribute_t ** 1323125Sjacobs parse_cf(papi_service_t svc, char *cf, char **files) 1332264Sjacobs { 1343125Sjacobs papi_attribute_t **list = NULL; 1353125Sjacobs char previous = NULL, 136*7132Sps29005 *entry; 137*7132Sps29005 int copies_set = 0, 1383125Sjacobs copies = 0; 1393125Sjacobs 1403125Sjacobs for (entry = strtok(cf, "\n"); entry != NULL; 1413125Sjacobs entry = strtok(NULL, "\n")) { 1423125Sjacobs char *format = NULL; 1433125Sjacobs 1443125Sjacobs /* count the copies */ 1453125Sjacobs if ((entry[0] >= 'a') && (entry[0] <= 'z') && 1463125Sjacobs (copies_set == 0) && (previous == entry[0])) 1473125Sjacobs copies++; 1483125Sjacobs else if ((previous >= 'a') && (previous <= 'z')) 1493125Sjacobs copies_set = 1; 1503125Sjacobs previous = entry[0]; 1512264Sjacobs 1523125Sjacobs /* process the control message */ 1533125Sjacobs switch (entry[0]) { 1543125Sjacobs /* RFC-1179 options */ 1553125Sjacobs case 'J': /* RFC-1179 Banner Job Name */ 1563125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1573125Sjacobs "job-name", ++entry); 1583125Sjacobs break; 1593125Sjacobs case 'C': /* RFC-1179 Banner Class Name */ 1603125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1613125Sjacobs "rfc-1179-class", ++entry); 1623125Sjacobs break; 1633125Sjacobs case 'L': /* RFC-1179 Banner toggle */ 1643125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1653125Sjacobs "job-sheets", "standard"); 1663125Sjacobs break; 1673125Sjacobs case 'T': /* RFC-1179 Title (pr) */ 1683125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1693125Sjacobs "pr-title", ++entry); 1703125Sjacobs break; 1713125Sjacobs case 'H': /* RFC-1179 Host */ 1723125Sjacobs /* 1733125Sjacobs * use the host as known by us, not by them 1743125Sjacobs * 1753125Sjacobs * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1763125Sjacobs * "job-originating-host-name", ++entry); 1773125Sjacobs */ 1783125Sjacobs break; 1793125Sjacobs case 'P': /* RFC-1179 User */ 1803125Sjacobs ++entry; 1813125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1823125Sjacobs "requesting-user-name", entry); 1833125Sjacobs papiServiceSetUserName(svc, entry); 1843125Sjacobs break; 1853125Sjacobs case 'M': /* RFC-1179 Mail to User */ 1863125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 1873125Sjacobs "rfc-1179-mail", 1); 1883125Sjacobs break; 1893125Sjacobs case 'W': /* RFC-1179 Width (pr) */ 1903125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 1913125Sjacobs "pr-width", atoi(++entry)); 1923125Sjacobs break; 1933125Sjacobs case 'I': /* RFC-1179 Indent (pr) */ 1943125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 1953125Sjacobs "pr-indent", atoi(++entry)); 1963125Sjacobs break; 1973125Sjacobs case 'N': /* RFC-1179 Filename */ 1983125Sjacobs /* could have HPUX extension embedded */ 1993125Sjacobs if (entry[1] != ' ') { /* real pathname */ 2003125Sjacobs #ifdef DEBUG 2013125Sjacobs papiAttributeListAddString(&list, 2023125Sjacobs PAPI_ATTR_EXCL, 2033125Sjacobs "flist", ++entry); 2043125Sjacobs #endif 2053125Sjacobs } else if (entry[2] == 'O') /* HPUX lp -o options */ 2063125Sjacobs papiAttributeListFromString(&list, 2073125Sjacobs PAPI_ATTR_APPEND, ++entry); 2083125Sjacobs break; 2093125Sjacobs case 'U': /* RFC-1179 Unlink */ 2103125Sjacobs break; /* ignored */ 2113125Sjacobs case '1': /* RFC-1179 TROFF Font R */ 2123125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2133125Sjacobs "rfc-1179-font-r", ++entry); 2143125Sjacobs break; 2153125Sjacobs case '2': /* RFC-1179 TROFF Font I */ 2163125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2173125Sjacobs "rfc-1179-font-i", ++entry); 2183125Sjacobs break; 2193125Sjacobs case '3': /* RFC-1179 TROFF Font B */ 2203125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2213125Sjacobs "rfc-1179-font-b", ++entry); 2223125Sjacobs break; 2233125Sjacobs case '4': /* RFC-1179 TROFF Font S */ 2243125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2253125Sjacobs "rfc-1179-font-s", ++entry); 2263125Sjacobs break; 2273125Sjacobs case 'f': /* RFC-1179 ASCII file (print) */ 2283125Sjacobs format = "text/plain"; 2293125Sjacobs if (is_postscript(files[0]) == 1) 2303125Sjacobs format = "application/postscript"; 2313125Sjacobs break; 2323125Sjacobs case 'l': /* RFC-1179 CATV file (print) */ 2333125Sjacobs format = "application/octet-stream"; 2343125Sjacobs if (is_postscript(files[0]) == 1) 2353125Sjacobs format = "application/postscript"; 2363125Sjacobs break; 2373125Sjacobs case 'o': /* RFC-1179 Postscript file (print) */ 2383125Sjacobs format = "application/postscript"; 2393125Sjacobs break; 2403125Sjacobs case 'p': /* RFC-1179 PR file (print) */ 2413125Sjacobs format = "application/x-pr"; 2423125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 2433125Sjacobs "pr-filter", 1); 2443125Sjacobs break; 2453125Sjacobs case 't': /* RFC-1179 TROFF file (print) */ 2463125Sjacobs format = "application/x-troff"; 2473125Sjacobs break; 2483125Sjacobs case 'n': /* RFC-1179 DITROFF file (print) */ 2493125Sjacobs format = "application/x-ditroff"; 2503125Sjacobs break; 2513125Sjacobs case 'd': /* RFC-1179 DVI file (print) */ 2523125Sjacobs format = "application/x-dvi"; 2533125Sjacobs break; 2543125Sjacobs case 'g': /* RFC-1179 GRAPH file (print) */ 2553125Sjacobs format = "application/x-plot"; 2563125Sjacobs break; 2573125Sjacobs case 'c': /* RFC-1179 CIF file (print) */ 2583125Sjacobs format = "application/x-cif"; 2593125Sjacobs break; 2603125Sjacobs case 'v': /* RFC-1179 RASTER file (print) */ 2613125Sjacobs format = "application/x-raster"; 2623125Sjacobs break; 2633125Sjacobs case 'r': /* RFC-1179 FORTRAN file (print) */ 2643125Sjacobs format = "application/x-fortran"; 2653125Sjacobs break; 2663125Sjacobs /* Sun Solaris Extensions */ 2673125Sjacobs case 'O': 2683125Sjacobs ++entry; 269*7132Sps29005 { 270*7132Sps29005 int rd, wr; 271*7132Sps29005 272*7132Sps29005 for (rd = wr = 0; entry[rd] != '\0'; rd++) { 273*7132Sps29005 if (entry[rd] == '"') 274*7132Sps29005 continue; 275*7132Sps29005 if (rd != wr) 276*7132Sps29005 entry[wr] = entry[rd]; 277*7132Sps29005 wr++; 278*7132Sps29005 } 279*7132Sps29005 entry[wr] = '\0'; 280*7132Sps29005 281*7132Sps29005 papiAttributeListFromString(&list, 282*7132Sps29005 PAPI_ATTR_APPEND, entry); 283*7132Sps29005 } 2843125Sjacobs break; 2853125Sjacobs case '5': 2863125Sjacobs ++entry; 2873125Sjacobs switch (entry[0]) { 2883125Sjacobs case 'f': /* Solaris form */ 2893125Sjacobs papiAttributeListAddString(&list, 2903125Sjacobs PAPI_ATTR_EXCL, 2913125Sjacobs "form", ++entry); 2923125Sjacobs break; 2933125Sjacobs case 'H': /* Solaris handling */ 2943125Sjacobs ++entry; 2953125Sjacobs if (strcasecmp(entry, "hold") == 0) 2963125Sjacobs papiAttributeListAddString(&list, 2973125Sjacobs PAPI_ATTR_EXCL, 2983125Sjacobs "job-hold-until", "indefinite"); 2996725Sjacobs else if (strcasecmp(entry, "immediate") == 0) 3003125Sjacobs papiAttributeListAddString(&list, 3013125Sjacobs PAPI_ATTR_EXCL, 3023125Sjacobs "job-hold-until", "no-hold"); 3033125Sjacobs else 3043125Sjacobs papiAttributeListAddString(&list, 3053125Sjacobs PAPI_ATTR_EXCL, 3063125Sjacobs "job-hold-until", entry); 3073125Sjacobs break; 3083125Sjacobs case 'p': /* Solaris notification */ 3093125Sjacobs papiAttributeListAddBoolean(&list, 3103125Sjacobs PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 3113125Sjacobs break; 3126725Sjacobs case 'P': { /* Solaris page list */ 3136725Sjacobs char buf[BUFSIZ]; 3146725Sjacobs 3156725Sjacobs snprintf(buf, sizeof (buf), "page-ranges=%s", 3166725Sjacobs ++entry); 3176728Sjacobs papiAttributeListFromString(&list, 3186725Sjacobs PAPI_ATTR_EXCL, buf); 3196725Sjacobs } 3203125Sjacobs break; 3213125Sjacobs case 'q': { /* Solaris priority */ 3223125Sjacobs int i = atoi(optarg); 3233125Sjacobs 3246725Sjacobs i = 100 - (i * 2.5); 3253125Sjacobs if ((i < 1) || (i > 100)) 3263125Sjacobs i = 50; 3273125Sjacobs papiAttributeListAddInteger(&list, 3286725Sjacobs PAPI_ATTR_EXCL, "job-priority", i); 3293125Sjacobs } 3303125Sjacobs break; 3313125Sjacobs case 'S': /* Solaris character set */ 3323125Sjacobs papiAttributeListAddString(&list, 3333125Sjacobs PAPI_ATTR_EXCL, "lp-charset", 3343125Sjacobs ++entry); 3353125Sjacobs break; 3363125Sjacobs case 'T': /* Solaris type */ 3373125Sjacobs format = lp_type_to_mime_type(++entry); 3383125Sjacobs break; 3393125Sjacobs case 'y': /* Solaris mode */ 3403125Sjacobs papiAttributeListAddString(&list, 3413125Sjacobs PAPI_ATTR_APPEND, "lp-modes", ++entry); 3423125Sjacobs break; 3433125Sjacobs default: 3443125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3453125Sjacobs "Warning: cf message (%s) ignored", 3463125Sjacobs entry); 3473125Sjacobs break; 3483125Sjacobs } 3493125Sjacobs break; 3503125Sjacobs /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 3513125Sjacobs 3523125Sjacobs default: 3533125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3543125Sjacobs "Warning: cf message (%s) ignored", entry); 3553125Sjacobs break; 3563125Sjacobs } 3573125Sjacobs 3583125Sjacobs if (format != NULL) 3593125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3603125Sjacobs "document-format", format); 3613125Sjacobs } 3623125Sjacobs 3633125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 3643125Sjacobs "copies", ++copies); 3653125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3663125Sjacobs "job-sheets", "none"); 3673125Sjacobs 3683125Sjacobs return (list); 3693125Sjacobs } 3703125Sjacobs 3713125Sjacobs static papi_status_t 3726817Sjacobs submit_job(papi_service_t svc, FILE *ifp, char *printer, int rid, char *cf, 3736817Sjacobs char **files) 3743125Sjacobs { 3753125Sjacobs papi_attribute_t **list = NULL; 3763125Sjacobs papi_status_t status; 3773125Sjacobs papi_job_t job = NULL; 3783125Sjacobs char *format = ""; 3793125Sjacobs 3803125Sjacobs if ((list = parse_cf(svc, cf, files)) != NULL) { 3813125Sjacobs /* use the host as known by us, not by them */ 3823125Sjacobs char *host = remote_host_name(ifp); 3833125Sjacobs 3843125Sjacobs if (host != NULL) { 3853125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 3863125Sjacobs "job-originating-host-name", host); 3873125Sjacobs free(host); 3883125Sjacobs } 3896817Sjacobs if (rid > 0) { 3906817Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 3916817Sjacobs "job-id-requested", rid); 3926817Sjacobs } 3933125Sjacobs } 3943125Sjacobs 3953125Sjacobs status = papiJobSubmit(svc, printer, list, NULL, files, &job); 3963125Sjacobs syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 3973125Sjacobs if (status != PAPI_OK) { 3983125Sjacobs char *tmp = papiServiceGetStatusMessage(svc); 3993125Sjacobs 4003125Sjacobs syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 4013125Sjacobs } 4023125Sjacobs papiJobFree(job); 4033125Sjacobs 4043125Sjacobs return (status); 4053125Sjacobs } 4063125Sjacobs 4073125Sjacobs static char * 4083125Sjacobs receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 4093125Sjacobs { 4103125Sjacobs char *ptr, *cf_data; 4113125Sjacobs 4123125Sjacobs if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 4133125Sjacobs NACK(ofp); 4143125Sjacobs return (NULL); 4153125Sjacobs } else 4163125Sjacobs ACK(ofp); 4173125Sjacobs 4183125Sjacobs while (size > 0) { 4193125Sjacobs int rc; 4203125Sjacobs 4213125Sjacobs if (((rc = fread(ptr, 1, size, ifp)) == 0) && 4223125Sjacobs (feof(ifp) != 0)) { 4233125Sjacobs free(cf_data); 4243125Sjacobs return (NULL); 4253125Sjacobs } else { 4263125Sjacobs ptr += rc; 4273125Sjacobs size -= rc; 4283125Sjacobs } 4293125Sjacobs } 4303125Sjacobs syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 4313125Sjacobs 4323125Sjacobs if (fgetc(ifp) != 0) { 4333125Sjacobs free(cf_data); 4343125Sjacobs return (NULL); 4353125Sjacobs } 4362264Sjacobs ACK(ofp); 4372264Sjacobs 4383125Sjacobs return (cf_data); 4393125Sjacobs } 4403125Sjacobs 4413125Sjacobs static char * 4423125Sjacobs receive_data_file(FILE *ifp, FILE *ofp, int size) 4433125Sjacobs { 4443125Sjacobs char file[] = "lpdXXXXXX"; 4453125Sjacobs char buf[BUFSIZ]; 4463125Sjacobs int fd; 4473125Sjacobs 4483125Sjacobs if ((fd = mkstemp(file)) < 0) { 4493125Sjacobs NACK(ofp); 4503125Sjacobs return (NULL); 4513125Sjacobs } else 4523125Sjacobs ACK(ofp); 4533125Sjacobs 4543125Sjacobs while (size > 0) { 4553125Sjacobs int rc = ((size > BUFSIZ) ? BUFSIZ : size); 4563125Sjacobs 4573125Sjacobs if (((rc = fread(buf, 1, rc, ifp)) == 0) && 4583125Sjacobs (feof(ifp) != 0)) { 4593125Sjacobs close(fd); 4603125Sjacobs unlink(file); 4613125Sjacobs return (NULL); 4623125Sjacobs } else { 4633125Sjacobs char *ptr = buf; 4643125Sjacobs 4653125Sjacobs while (rc > 0) { 4663125Sjacobs int wrc = write(fd, ptr, rc); 4673125Sjacobs 4683125Sjacobs if (wrc < 0) { 4693125Sjacobs close(fd); 4703125Sjacobs unlink(file); 4713127Sjacobs return (NULL); 4723125Sjacobs } 4733125Sjacobs 4743125Sjacobs ptr += wrc; 4753125Sjacobs size -= wrc; 4763125Sjacobs rc -= wrc; 4773125Sjacobs } 4783125Sjacobs } 4793125Sjacobs } 4803125Sjacobs close(fd); 4813125Sjacobs if (fgetc(ifp) != 0) { 4823125Sjacobs unlink(file); 4833125Sjacobs return (NULL); 4843125Sjacobs } 4853125Sjacobs ACK(ofp); 4863125Sjacobs 4873125Sjacobs return (strdup(file)); 4883125Sjacobs } 4893127Sjacobs 4903125Sjacobs static papi_status_t 4913125Sjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 4923125Sjacobs { 4933125Sjacobs papi_status_t status = PAPI_OK; 4943125Sjacobs char *file, **files = NULL; /* the job data files */ 4953125Sjacobs char *cf = NULL; 4966817Sjacobs int rid = 0; 4973125Sjacobs char buf[BUFSIZ]; 4983125Sjacobs 4993125Sjacobs while (fgets(buf, sizeof (buf), ifp) != NULL) { 5003125Sjacobs int size; 5013125Sjacobs 5023125Sjacobs syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 5033125Sjacobs #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 5043125Sjacobs if ((buf[0] > '0') && (buf[0] < '4')) 5053125Sjacobs buf[0] -= '0'; 5063125Sjacobs #endif 5073125Sjacobs switch (buf[0]) { 5082264Sjacobs case 0x01: /* Abort */ 5093125Sjacobs cleanup(&files, &cf); 5102264Sjacobs break; 5113125Sjacobs case 0x02: { /* Receive control file */ 5126817Sjacobs if (((cf = strchr(buf, ' ')) != NULL) && 5136817Sjacobs (strlen(cf) > 4)) { 5146817Sjacobs while ((*cf != NULL) && (isdigit(*cf) == 0)) 5156817Sjacobs cf++; 5166817Sjacobs rid = atoi(cf); 5176817Sjacobs } 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) { 5236817Sjacobs status = submit_job(svc, ifp, printer, rid, 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)) 5466817Sjacobs status = submit_job(svc, ifp, printer, rid, 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 uri_t *uri = NULL; 5873125Sjacobs char *s = NULL; 5883125Sjacobs 5893125Sjacobs /* was there a printer? */ 5903125Sjacobs if (svc_name == NULL) 5913125Sjacobs return (0); 5923125Sjacobs 5933125Sjacobs if ((list = getprinterbyname(svc_name, NULL)) == NULL) 5943127Sjacobs return (0); /* if it doesnt' resolve, we will fail later */ 5953125Sjacobs 5963125Sjacobs papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 5973125Sjacobs if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 5983127Sjacobs return (0); /* they don't match */ 5993125Sjacobs 6003125Sjacobs /* is it in uri form? */ 6013125Sjacobs if (uri_from_string(s, &uri) < 0) 6023125Sjacobs return (0); 6033125Sjacobs 6043125Sjacobs if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 6053125Sjacobs uri_free(uri); 6063125Sjacobs return (0); 6073125Sjacobs } 6083125Sjacobs 6093125Sjacobs /* is it in lpd form? */ 6103125Sjacobs if (strcasecmp(uri->scheme, "lpd") != 0) { 6113125Sjacobs uri_free(uri); 6123125Sjacobs return (0); 6133125Sjacobs } 6143125Sjacobs 6153125Sjacobs /* is it the local host? */ 616*7132Sps29005 if (is_localhost(uri->host) != 0) { 6173125Sjacobs uri_free(uri); 6183125Sjacobs return (0); 6193125Sjacobs } 6203125Sjacobs 6213125Sjacobs uri_free(uri); 6223125Sjacobs return (1); 6233125Sjacobs } 6243125Sjacobs 6253125Sjacobs 6262264Sjacobs /* 6272264Sjacobs * This is the entry point for this program. The program takes the 6282264Sjacobs * following options: 6292264Sjacobs * (none) 6302264Sjacobs */ 6312264Sjacobs int 6322264Sjacobs main(int ac, char *av[]) 6332264Sjacobs { 6342264Sjacobs papi_status_t status; 6352264Sjacobs papi_service_t svc = NULL; 6362264Sjacobs papi_encryption_t encryption = PAPI_ENCRYPT_NEVER; 6372264Sjacobs FILE *ifp = stdin, 6382264Sjacobs *ofp = stdout; 6392264Sjacobs int c; 6402264Sjacobs char buf[BUFSIZ], 6412264Sjacobs **args, 6423125Sjacobs *printer, 6433125Sjacobs *run_dir = "/var/run/in.lpd", 6443125Sjacobs *run_user = NULL; 6453125Sjacobs struct passwd *pw = NULL; 6462264Sjacobs 6473125Sjacobs (void) chdir("/tmp"); /* run in /tmp by default */ 6482264Sjacobs openlog("bsd-gw", LOG_PID, LOG_LPR); 6492264Sjacobs 6503125Sjacobs while ((c = getopt(ac, av, "Ed:u:")) != EOF) 6512264Sjacobs switch (c) { 6522264Sjacobs case 'E': 6532264Sjacobs encryption = PAPI_ENCRYPT_ALWAYS; 6542264Sjacobs break; 6553125Sjacobs case 'd': /* run where they tell you */ 6563125Sjacobs run_dir = optarg; 6573125Sjacobs break; 6583125Sjacobs case 'u': /* run as */ 6593125Sjacobs run_user = optarg; 6603125Sjacobs break; 6612264Sjacobs default: 6622264Sjacobs ; 6632264Sjacobs } 6642264Sjacobs 6653125Sjacobs if (run_user != NULL) /* get the requested user info */ 6663125Sjacobs pw = getpwnam(run_user); 6673127Sjacobs 6683125Sjacobs if (run_dir != NULL) { /* setup the run_dir */ 6693125Sjacobs (void) mkdir(run_dir, 0700); 6703125Sjacobs if (pw != NULL) 6713125Sjacobs (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 6723125Sjacobs } 6733125Sjacobs 6743125Sjacobs if (pw != NULL) { /* run as the requested user */ 6753127Sjacobs syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 6763125Sjacobs pw->pw_name, pw->pw_uid, pw->pw_gid); 6773125Sjacobs initgroups(pw->pw_name, pw->pw_gid); 6783125Sjacobs setgid(pw->pw_gid); 6793125Sjacobs setuid(pw->pw_uid); 6803125Sjacobs } 6813125Sjacobs 6823125Sjacobs if (run_dir != NULL) /* move to the run_dir */ 6833125Sjacobs if (chdir(run_dir) < 0) { 6843125Sjacobs syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 6853125Sjacobs exit(1); 6863125Sjacobs } 6873125Sjacobs 6883125Sjacobs syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 6893125Sjacobs 6902264Sjacobs if (fgets(buf, sizeof (buf), ifp) == NULL) { 6912264Sjacobs if (feof(ifp) == 0) 6922264Sjacobs syslog(LOG_ERR, "Error reading from connection: %s", 6932264Sjacobs strerror(errno)); 6942264Sjacobs exit(1); 6952264Sjacobs } 6962264Sjacobs 6973125Sjacobs syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 6983125Sjacobs 6993125Sjacobs #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 7003125Sjacobs if ((buf[0] > '0') && (buf[0] < '6')) 7013125Sjacobs buf[0] -= '0'; 7023125Sjacobs #endif 7033125Sjacobs 7042264Sjacobs if ((buf[0] < 1) || (buf[0] > 5)) { 7052264Sjacobs fatal(ofp, "Invalid protocol request (%d): %c%s\n", 7062264Sjacobs buf[0], buf[0], buf); 7072264Sjacobs exit(1); 7082264Sjacobs } 7092264Sjacobs 7102264Sjacobs args = strsplit(&buf[1], "\t\n "); 7112264Sjacobs printer = *args++; 7122264Sjacobs 7132264Sjacobs if (printer == NULL) { 7142264Sjacobs fatal(ofp, "Can't determine requested printer"); 7152264Sjacobs exit(1); 7162264Sjacobs } 7172264Sjacobs 7183125Sjacobs if (cyclical_service_check(printer) != 0) { 7193125Sjacobs fatal(ofp, "%s is cyclical\n", printer); 7203125Sjacobs exit(1); 7213125Sjacobs } 7223125Sjacobs 7232264Sjacobs status = papiServiceCreate(&svc, printer, NULL, NULL, NULL, 7242264Sjacobs encryption, NULL); 7252264Sjacobs if (status != PAPI_OK) { 7262264Sjacobs fatal(ofp, "Failed to contact service for %s: %s\n", printer, 7272264Sjacobs verbose_papi_message(svc, status)); 7282264Sjacobs exit(1); 7292264Sjacobs } 7302264Sjacobs 7313125Sjacobs /* 7323125Sjacobs * Trusted Solaris can't be trusting of intermediaries. Pass 7333125Sjacobs * the socket connection to the print service to retrieve the 7343125Sjacobs * sensativity label off of a multi-level port. 7353125Sjacobs */ 7363125Sjacobs (void) papiServiceSetPeer(svc, fileno(ifp)); 7372264Sjacobs 7382264Sjacobs switch (buf[0]) { 7392264Sjacobs case '\1': /* restart printer */ 7402264Sjacobs ACK(ofp); /* there is no equivalent */ 7412264Sjacobs break; 7422264Sjacobs case '\2': /* transfer job(s) */ 7433125Sjacobs status = berkeley_transfer_files(svc, ifp, ofp, printer); 7442264Sjacobs break; 7452264Sjacobs case '\3': /* show queue (short) */ 7462264Sjacobs case '\4': { /* show queue (long) */ 7472264Sjacobs int count; 7482264Sjacobs 7492264Sjacobs for (count = 0; args[count] != 0; count++); 7502264Sjacobs 7512264Sjacobs berkeley_queue_report(svc, ofp, printer, buf[0], count, args); 7522264Sjacobs } 7532264Sjacobs break; 7542264Sjacobs case '\5': { /* cancel job(s) */ 7553125Sjacobs char *user = *args++; 7563125Sjacobs char *host = remote_host_name(ifp); 7572264Sjacobs int count; 7582264Sjacobs 7593125Sjacobs if (host != NULL) { 7603125Sjacobs char buf[BUFSIZ]; 7613125Sjacobs 7623125Sjacobs snprintf(buf, sizeof (buf), "%s@%s", user, host); 7633125Sjacobs status = papiServiceSetUserName(svc, buf); 7643125Sjacobs } else 7653125Sjacobs status = papiServiceSetUserName(svc, user); 7663125Sjacobs 7672264Sjacobs for (count = 0; args[count] != 0; count++); 7682264Sjacobs 7692264Sjacobs berkeley_cancel_request(svc, ofp, printer, count, args); 7702264Sjacobs } 7712264Sjacobs break; 7722264Sjacobs default: 7732264Sjacobs fatal(ofp, "unsupported protocol request (%c), %s", 7742264Sjacobs buf[0], &buf[1]); 7752264Sjacobs } 7762264Sjacobs 7772264Sjacobs (void) fflush(ofp); 7782264Sjacobs 7792264Sjacobs syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s", 7802264Sjacobs buf[0], printer, papiStatusString(status)); 7813125Sjacobs if (status != PAPI_OK) 7823125Sjacobs syslog(LOG_DEBUG, "detail: %s", 7833125Sjacobs verbose_papi_message(svc, status)); 7842264Sjacobs 7852264Sjacobs papiServiceDestroy(svc); 7862264Sjacobs 7872264Sjacobs return (0); 7882264Sjacobs } 789