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> 38*6817Sjacobs #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; 723125Sjacobs char myname[MAXHOSTNAMELEN], 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 913125Sjacobs /* is it "localhost" ? */ 923125Sjacobs if (strcasecmp(hp->h_name, "localhost") == 0) 933125Sjacobs return (strdup("localhost")); 943125Sjacobs 953125Sjacobs /* duplicate the name because gethostbyXXXX() is not reentrant */ 963125Sjacobs hostname = strdup(hp->h_name); 973125Sjacobs (void) sysinfo(SI_HOSTNAME, myname, sizeof (myname)); 983125Sjacobs 993125Sjacobs /* is it from one of my addresses ? */ 1003125Sjacobs if ((hp = getipnodebyname(myname, AF_INET6, AI_ALL|AI_V4MAPPED, 1013125Sjacobs &error_num)) != NULL) { 1023125Sjacobs struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list; 1033125Sjacobs int i = 0; 1043125Sjacobs 1053125Sjacobs while (tmp[i] != NULL) { 1063125Sjacobs if (memcmp(tmp[i++], &peer.sin6_addr, hp->h_length) 1073125Sjacobs == 0) { 1083125Sjacobs free(hostname); 1093125Sjacobs return (strdup("localhost")); 1103125Sjacobs } 1113125Sjacobs } 1123125Sjacobs } 1133125Sjacobs 1143125Sjacobs /* It must be someone else */ 1153125Sjacobs return (hostname); 1163125Sjacobs } 1173125Sjacobs 1183125Sjacobs static void 1192264Sjacobs fatal(FILE *fp, char *fmt, ...) 1202264Sjacobs { 1212264Sjacobs va_list ap; 1222264Sjacobs 1232264Sjacobs va_start(ap, fmt); 1242264Sjacobs vsyslog(LOG_DEBUG, fmt, ap); 1252264Sjacobs vfprintf(fp, fmt, ap); 1262264Sjacobs va_end(ap); 1273125Sjacobs exit(1); 1282264Sjacobs } 1292264Sjacobs 1302264Sjacobs static void 1313125Sjacobs cleanup(char ***files, char **cf) 1323125Sjacobs { 1333125Sjacobs if (*files != NULL) { 1343125Sjacobs int i; 1353125Sjacobs 1363125Sjacobs for (i = 0; (*files)[i] != NULL; i++) { 1373125Sjacobs (void) unlink((*files)[i]); 1383125Sjacobs free((*files)[i]); 1393125Sjacobs } 1403125Sjacobs free(*files); 1413125Sjacobs *files = NULL; 1423125Sjacobs } 1433125Sjacobs 1443125Sjacobs if (*cf != NULL) { 1453125Sjacobs free(*cf); 1463125Sjacobs *cf = NULL; 1473125Sjacobs } 1483125Sjacobs } 1493125Sjacobs 1503125Sjacobs static papi_attribute_t ** 1513125Sjacobs parse_cf(papi_service_t svc, char *cf, char **files) 1522264Sjacobs { 1533125Sjacobs papi_attribute_t **list = NULL; 1543125Sjacobs char previous = NULL, 1553125Sjacobs *entry, 1563125Sjacobs *s, 1573125Sjacobs text[BUFSIZ]; 1583125Sjacobs int count = 0, 1593125Sjacobs copies_set = 0, 1603125Sjacobs copies = 0; 1613125Sjacobs 1623125Sjacobs for (entry = strtok(cf, "\n"); entry != NULL; 1633125Sjacobs entry = strtok(NULL, "\n")) { 1643125Sjacobs char *format = NULL; 1653125Sjacobs 1663125Sjacobs /* count the copies */ 1673125Sjacobs if ((entry[0] >= 'a') && (entry[0] <= 'z') && 1683125Sjacobs (copies_set == 0) && (previous == entry[0])) 1693125Sjacobs copies++; 1703125Sjacobs else if ((previous >= 'a') && (previous <= 'z')) 1713125Sjacobs copies_set = 1; 1723125Sjacobs previous = entry[0]; 1732264Sjacobs 1743125Sjacobs /* process the control message */ 1753125Sjacobs switch (entry[0]) { 1763125Sjacobs /* RFC-1179 options */ 1773125Sjacobs case 'J': /* RFC-1179 Banner Job Name */ 1783125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1793125Sjacobs "job-name", ++entry); 1803125Sjacobs break; 1813125Sjacobs case 'C': /* RFC-1179 Banner Class Name */ 1823125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1833125Sjacobs "rfc-1179-class", ++entry); 1843125Sjacobs break; 1853125Sjacobs case 'L': /* RFC-1179 Banner toggle */ 1863125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1873125Sjacobs "job-sheets", "standard"); 1883125Sjacobs break; 1893125Sjacobs case 'T': /* RFC-1179 Title (pr) */ 1903125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1913125Sjacobs "pr-title", ++entry); 1923125Sjacobs break; 1933125Sjacobs case 'H': /* RFC-1179 Host */ 1943125Sjacobs /* 1953125Sjacobs * use the host as known by us, not by them 1963125Sjacobs * 1973125Sjacobs * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 1983125Sjacobs * "job-originating-host-name", ++entry); 1993125Sjacobs */ 2003125Sjacobs break; 2013125Sjacobs case 'P': /* RFC-1179 User */ 2023125Sjacobs ++entry; 2033125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2043125Sjacobs "requesting-user-name", entry); 2053125Sjacobs papiServiceSetUserName(svc, entry); 2063125Sjacobs break; 2073125Sjacobs case 'M': /* RFC-1179 Mail to User */ 2083125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 2093125Sjacobs "rfc-1179-mail", 1); 2103125Sjacobs break; 2113125Sjacobs case 'W': /* RFC-1179 Width (pr) */ 2123125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 2133125Sjacobs "pr-width", atoi(++entry)); 2143125Sjacobs break; 2153125Sjacobs case 'I': /* RFC-1179 Indent (pr) */ 2163125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 2173125Sjacobs "pr-indent", atoi(++entry)); 2183125Sjacobs break; 2193125Sjacobs case 'N': /* RFC-1179 Filename */ 2203125Sjacobs /* could have HPUX extension embedded */ 2213125Sjacobs if (entry[1] != ' ') { /* real pathname */ 2223125Sjacobs #ifdef DEBUG 2233125Sjacobs papiAttributeListAddString(&list, 2243125Sjacobs PAPI_ATTR_EXCL, 2253125Sjacobs "flist", ++entry); 2263125Sjacobs #endif 2273125Sjacobs } else if (entry[2] == 'O') /* HPUX lp -o options */ 2283125Sjacobs papiAttributeListFromString(&list, 2293125Sjacobs PAPI_ATTR_APPEND, ++entry); 2303125Sjacobs break; 2313125Sjacobs case 'U': /* RFC-1179 Unlink */ 2323125Sjacobs break; /* ignored */ 2333125Sjacobs case '1': /* RFC-1179 TROFF Font R */ 2343125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2353125Sjacobs "rfc-1179-font-r", ++entry); 2363125Sjacobs break; 2373125Sjacobs case '2': /* RFC-1179 TROFF Font I */ 2383125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2393125Sjacobs "rfc-1179-font-i", ++entry); 2403125Sjacobs break; 2413125Sjacobs case '3': /* RFC-1179 TROFF Font B */ 2423125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2433125Sjacobs "rfc-1179-font-b", ++entry); 2443125Sjacobs break; 2453125Sjacobs case '4': /* RFC-1179 TROFF Font S */ 2463125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 2473125Sjacobs "rfc-1179-font-s", ++entry); 2483125Sjacobs break; 2493125Sjacobs case 'f': /* RFC-1179 ASCII file (print) */ 2503125Sjacobs format = "text/plain"; 2513125Sjacobs if (is_postscript(files[0]) == 1) 2523125Sjacobs format = "application/postscript"; 2533125Sjacobs break; 2543125Sjacobs case 'l': /* RFC-1179 CATV file (print) */ 2553125Sjacobs format = "application/octet-stream"; 2563125Sjacobs if (is_postscript(files[0]) == 1) 2573125Sjacobs format = "application/postscript"; 2583125Sjacobs break; 2593125Sjacobs case 'o': /* RFC-1179 Postscript file (print) */ 2603125Sjacobs format = "application/postscript"; 2613125Sjacobs break; 2623125Sjacobs case 'p': /* RFC-1179 PR file (print) */ 2633125Sjacobs format = "application/x-pr"; 2643125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 2653125Sjacobs "pr-filter", 1); 2663125Sjacobs break; 2673125Sjacobs case 't': /* RFC-1179 TROFF file (print) */ 2683125Sjacobs format = "application/x-troff"; 2693125Sjacobs break; 2703125Sjacobs case 'n': /* RFC-1179 DITROFF file (print) */ 2713125Sjacobs format = "application/x-ditroff"; 2723125Sjacobs break; 2733125Sjacobs case 'd': /* RFC-1179 DVI file (print) */ 2743125Sjacobs format = "application/x-dvi"; 2753125Sjacobs break; 2763125Sjacobs case 'g': /* RFC-1179 GRAPH file (print) */ 2773125Sjacobs format = "application/x-plot"; 2783125Sjacobs break; 2793125Sjacobs case 'c': /* RFC-1179 CIF file (print) */ 2803125Sjacobs format = "application/x-cif"; 2813125Sjacobs break; 2823125Sjacobs case 'v': /* RFC-1179 RASTER file (print) */ 2833125Sjacobs format = "application/x-raster"; 2843125Sjacobs break; 2853125Sjacobs case 'r': /* RFC-1179 FORTRAN file (print) */ 2863125Sjacobs format = "application/x-fortran"; 2873125Sjacobs break; 2883125Sjacobs /* Sun Solaris Extensions */ 2893125Sjacobs case 'O': 2903125Sjacobs ++entry; 2913125Sjacobs do { 2923125Sjacobs if (*entry != '"') 2933125Sjacobs text[count++] = *entry; 2943125Sjacobs } while (*entry++); 2953125Sjacobs papiAttributeListFromString(&list, PAPI_ATTR_APPEND, 2963125Sjacobs text); 2973125Sjacobs break; 2983125Sjacobs case '5': 2993125Sjacobs ++entry; 3003125Sjacobs switch (entry[0]) { 3013125Sjacobs case 'f': /* Solaris form */ 3023125Sjacobs papiAttributeListAddString(&list, 3033125Sjacobs PAPI_ATTR_EXCL, 3043125Sjacobs "form", ++entry); 3053125Sjacobs break; 3063125Sjacobs case 'H': /* Solaris handling */ 3073125Sjacobs ++entry; 3083125Sjacobs if (strcasecmp(entry, "hold") == 0) 3093125Sjacobs papiAttributeListAddString(&list, 3103125Sjacobs PAPI_ATTR_EXCL, 3113125Sjacobs "job-hold-until", "indefinite"); 3126725Sjacobs else if (strcasecmp(entry, "immediate") == 0) 3133125Sjacobs papiAttributeListAddString(&list, 3143125Sjacobs PAPI_ATTR_EXCL, 3153125Sjacobs "job-hold-until", "no-hold"); 3163125Sjacobs else 3173125Sjacobs papiAttributeListAddString(&list, 3183125Sjacobs PAPI_ATTR_EXCL, 3193125Sjacobs "job-hold-until", entry); 3203125Sjacobs break; 3213125Sjacobs case 'p': /* Solaris notification */ 3223125Sjacobs papiAttributeListAddBoolean(&list, 3233125Sjacobs PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 3243125Sjacobs break; 3256725Sjacobs case 'P': { /* Solaris page list */ 3266725Sjacobs char buf[BUFSIZ]; 3276725Sjacobs 3286725Sjacobs snprintf(buf, sizeof (buf), "page-ranges=%s", 3296725Sjacobs ++entry); 3306728Sjacobs papiAttributeListFromString(&list, 3316725Sjacobs PAPI_ATTR_EXCL, buf); 3326725Sjacobs } 3333125Sjacobs break; 3343125Sjacobs case 'q': { /* Solaris priority */ 3353125Sjacobs int i = atoi(optarg); 3363125Sjacobs 3376725Sjacobs i = 100 - (i * 2.5); 3383125Sjacobs if ((i < 1) || (i > 100)) 3393125Sjacobs i = 50; 3403125Sjacobs papiAttributeListAddInteger(&list, 3416725Sjacobs PAPI_ATTR_EXCL, "job-priority", i); 3423125Sjacobs } 3433125Sjacobs break; 3443125Sjacobs case 'S': /* Solaris character set */ 3453125Sjacobs papiAttributeListAddString(&list, 3463125Sjacobs PAPI_ATTR_EXCL, "lp-charset", 3473125Sjacobs ++entry); 3483125Sjacobs break; 3493125Sjacobs case 'T': /* Solaris type */ 3503125Sjacobs format = lp_type_to_mime_type(++entry); 3513125Sjacobs break; 3523125Sjacobs case 'y': /* Solaris mode */ 3533125Sjacobs papiAttributeListAddString(&list, 3543125Sjacobs PAPI_ATTR_APPEND, "lp-modes", ++entry); 3553125Sjacobs break; 3563125Sjacobs default: 3573125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3583125Sjacobs "Warning: cf message (%s) ignored", 3593125Sjacobs entry); 3603125Sjacobs break; 3613125Sjacobs } 3623125Sjacobs break; 3633125Sjacobs /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 3643125Sjacobs 3653125Sjacobs default: 3663125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 3673125Sjacobs "Warning: cf message (%s) ignored", entry); 3683125Sjacobs break; 3693125Sjacobs } 3703125Sjacobs 3713125Sjacobs if (format != NULL) 3723125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3733125Sjacobs "document-format", format); 3743125Sjacobs } 3753125Sjacobs 3763125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 3773125Sjacobs "copies", ++copies); 3783125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 3793125Sjacobs "job-sheets", "none"); 3803125Sjacobs 3813125Sjacobs return (list); 3823125Sjacobs } 3833125Sjacobs 3843125Sjacobs static papi_status_t 385*6817Sjacobs submit_job(papi_service_t svc, FILE *ifp, char *printer, int rid, char *cf, 386*6817Sjacobs char **files) 3873125Sjacobs { 3883125Sjacobs papi_attribute_t **list = NULL; 3893125Sjacobs papi_status_t status; 3903125Sjacobs papi_job_t job = NULL; 3913125Sjacobs char *format = ""; 3923125Sjacobs 3933125Sjacobs if ((list = parse_cf(svc, cf, files)) != NULL) { 3943125Sjacobs /* use the host as known by us, not by them */ 3953125Sjacobs char *host = remote_host_name(ifp); 3963125Sjacobs 3973125Sjacobs if (host != NULL) { 3983125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 3993125Sjacobs "job-originating-host-name", host); 4003125Sjacobs free(host); 4013125Sjacobs } 402*6817Sjacobs if (rid > 0) { 403*6817Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 404*6817Sjacobs "job-id-requested", rid); 405*6817Sjacobs } 4063125Sjacobs } 4073125Sjacobs 4083125Sjacobs status = papiJobSubmit(svc, printer, list, NULL, files, &job); 4093125Sjacobs syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 4103125Sjacobs if (status != PAPI_OK) { 4113125Sjacobs char *tmp = papiServiceGetStatusMessage(svc); 4123125Sjacobs 4133125Sjacobs syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 4143125Sjacobs } 4153125Sjacobs papiJobFree(job); 4163125Sjacobs 4173125Sjacobs return (status); 4183125Sjacobs } 4193125Sjacobs 4203125Sjacobs static char * 4213125Sjacobs receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 4223125Sjacobs { 4233125Sjacobs char *ptr, *cf_data; 4243125Sjacobs 4253125Sjacobs if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 4263125Sjacobs NACK(ofp); 4273125Sjacobs return (NULL); 4283125Sjacobs } else 4293125Sjacobs ACK(ofp); 4303125Sjacobs 4313125Sjacobs while (size > 0) { 4323125Sjacobs int rc; 4333125Sjacobs 4343125Sjacobs if (((rc = fread(ptr, 1, size, ifp)) == 0) && 4353125Sjacobs (feof(ifp) != 0)) { 4363125Sjacobs free(cf_data); 4373125Sjacobs return (NULL); 4383125Sjacobs } else { 4393125Sjacobs ptr += rc; 4403125Sjacobs size -= rc; 4413125Sjacobs } 4423125Sjacobs } 4433125Sjacobs syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 4443125Sjacobs 4453125Sjacobs if (fgetc(ifp) != 0) { 4463125Sjacobs free(cf_data); 4473125Sjacobs return (NULL); 4483125Sjacobs } 4492264Sjacobs ACK(ofp); 4502264Sjacobs 4513125Sjacobs return (cf_data); 4523125Sjacobs } 4533125Sjacobs 4543125Sjacobs static char * 4553125Sjacobs receive_data_file(FILE *ifp, FILE *ofp, int size) 4563125Sjacobs { 4573125Sjacobs char file[] = "lpdXXXXXX"; 4583125Sjacobs char buf[BUFSIZ]; 4593125Sjacobs int fd; 4603125Sjacobs 4613125Sjacobs if ((fd = mkstemp(file)) < 0) { 4623125Sjacobs NACK(ofp); 4633125Sjacobs return (NULL); 4643125Sjacobs } else 4653125Sjacobs ACK(ofp); 4663125Sjacobs 4673125Sjacobs while (size > 0) { 4683125Sjacobs int rc = ((size > BUFSIZ) ? BUFSIZ : size); 4693125Sjacobs 4703125Sjacobs if (((rc = fread(buf, 1, rc, ifp)) == 0) && 4713125Sjacobs (feof(ifp) != 0)) { 4723125Sjacobs close(fd); 4733125Sjacobs unlink(file); 4743125Sjacobs return (NULL); 4753125Sjacobs } else { 4763125Sjacobs char *ptr = buf; 4773125Sjacobs 4783125Sjacobs while (rc > 0) { 4793125Sjacobs int wrc = write(fd, ptr, rc); 4803125Sjacobs 4813125Sjacobs if (wrc < 0) { 4823125Sjacobs close(fd); 4833125Sjacobs unlink(file); 4843127Sjacobs return (NULL); 4853125Sjacobs } 4863125Sjacobs 4873125Sjacobs ptr += wrc; 4883125Sjacobs size -= wrc; 4893125Sjacobs rc -= wrc; 4903125Sjacobs } 4913125Sjacobs } 4923125Sjacobs } 4933125Sjacobs close(fd); 4943125Sjacobs if (fgetc(ifp) != 0) { 4953125Sjacobs unlink(file); 4963125Sjacobs return (NULL); 4973125Sjacobs } 4983125Sjacobs ACK(ofp); 4993125Sjacobs 5003125Sjacobs return (strdup(file)); 5013125Sjacobs } 5023127Sjacobs 5033125Sjacobs static papi_status_t 5043125Sjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 5053125Sjacobs { 5063125Sjacobs papi_status_t status = PAPI_OK; 5073125Sjacobs char *file, **files = NULL; /* the job data files */ 5083125Sjacobs char *cf = NULL; 509*6817Sjacobs int rid = 0; 5103125Sjacobs char buf[BUFSIZ]; 5113125Sjacobs 5123125Sjacobs while (fgets(buf, sizeof (buf), ifp) != NULL) { 5133125Sjacobs int size; 5143125Sjacobs 5153125Sjacobs syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 5163125Sjacobs #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 5173125Sjacobs if ((buf[0] > '0') && (buf[0] < '4')) 5183125Sjacobs buf[0] -= '0'; 5193125Sjacobs #endif 5203125Sjacobs switch (buf[0]) { 5212264Sjacobs case 0x01: /* Abort */ 5223125Sjacobs cleanup(&files, &cf); 5232264Sjacobs break; 5243125Sjacobs case 0x02: { /* Receive control file */ 525*6817Sjacobs if (((cf = strchr(buf, ' ')) != NULL) && 526*6817Sjacobs (strlen(cf) > 4)) { 527*6817Sjacobs while ((*cf != NULL) && (isdigit(*cf) == 0)) 528*6817Sjacobs cf++; 529*6817Sjacobs rid = atoi(cf); 530*6817Sjacobs } 5313125Sjacobs cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1])); 5323125Sjacobs if (cf == NULL) { 5333125Sjacobs cleanup(&files, &cf); 5343125Sjacobs return (PAPI_BAD_REQUEST); 5353125Sjacobs } else if (files != NULL) { 536*6817Sjacobs status = submit_job(svc, ifp, printer, rid, cf, 5373125Sjacobs files); 5383125Sjacobs cleanup(&files, &cf); 5393125Sjacobs } 5403125Sjacobs } 5412264Sjacobs break; 5422264Sjacobs case 0x03: { /* Receive data file */ 5433125Sjacobs file = receive_data_file(ifp, ofp, atoi(&buf[1])); 5443125Sjacobs if (file == NULL) { 5453125Sjacobs cleanup(&files, &cf); 5463125Sjacobs return (PAPI_TEMPORARY_ERROR); 5473125Sjacobs } 5483125Sjacobs list_append(&files, file); 5492264Sjacobs } 5502264Sjacobs break; 5512264Sjacobs default: 5523125Sjacobs cleanup(&files, &cf); 5532264Sjacobs fatal(ofp, "protocol screwup"); 5542264Sjacobs break; 5552264Sjacobs } 5562264Sjacobs } 5572264Sjacobs 5583125Sjacobs if ((cf != NULL) && (files != NULL)) 559*6817Sjacobs status = submit_job(svc, ifp, printer, rid, cf, files); 5603125Sjacobs 5613125Sjacobs cleanup(&files, &cf); 5623125Sjacobs 5633125Sjacobs return (status); 5642264Sjacobs } 5652264Sjacobs 5663125Sjacobs static papi_status_t 5672264Sjacobs berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp, 5682264Sjacobs char *printer) 5692264Sjacobs { 5702264Sjacobs papi_status_t status; 5712264Sjacobs papi_printer_t p = NULL; 5723125Sjacobs char *keys[] = { "printer-is-accepting-jobs", NULL }; 5732264Sjacobs 5742264Sjacobs status = papiPrinterQuery(svc, printer, keys, NULL, &p); 5752264Sjacobs if ((status == PAPI_OK) && (p != NULL)) { 5762264Sjacobs papi_attribute_t **attrs = papiPrinterGetAttributeList(p); 5772264Sjacobs char accepting = PAPI_FALSE; 5782264Sjacobs 5792264Sjacobs papiAttributeListGetBoolean(attrs, NULL, 5803125Sjacobs "printer-is-accepting-jobs", &accepting); 5812264Sjacobs 5823125Sjacobs if (accepting == PAPI_TRUE) { 5833125Sjacobs ACK(ofp); 5843125Sjacobs status = berkeley_receive_files(svc, ifp, ofp, printer); 5853125Sjacobs } else 5862264Sjacobs NACK(ofp); 5872264Sjacobs 5882264Sjacobs papiPrinterFree(p); 5892264Sjacobs } else 5902264Sjacobs NACK(ofp); 5913125Sjacobs 5923125Sjacobs return (status); 5932264Sjacobs } 5942264Sjacobs 5953125Sjacobs static int 5963125Sjacobs cyclical_service_check(char *svc_name) 5973125Sjacobs { 5983125Sjacobs papi_attribute_t **list; 5993125Sjacobs char buf[BUFSIZ]; 6003125Sjacobs uri_t *uri = NULL; 6013125Sjacobs char *s = NULL; 6023125Sjacobs 6033125Sjacobs /* was there a printer? */ 6043125Sjacobs if (svc_name == NULL) 6053125Sjacobs return (0); 6063125Sjacobs 6073125Sjacobs if ((list = getprinterbyname(svc_name, NULL)) == NULL) 6083127Sjacobs return (0); /* if it doesnt' resolve, we will fail later */ 6093125Sjacobs 6103125Sjacobs papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 6113125Sjacobs if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 6123127Sjacobs return (0); /* they don't match */ 6133125Sjacobs 6143125Sjacobs /* is it in uri form? */ 6153125Sjacobs if (uri_from_string(s, &uri) < 0) 6163125Sjacobs return (0); 6173125Sjacobs 6183125Sjacobs if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 6193125Sjacobs uri_free(uri); 6203125Sjacobs return (0); 6213125Sjacobs } 6223125Sjacobs 6233125Sjacobs /* is it in lpd form? */ 6243125Sjacobs if (strcasecmp(uri->scheme, "lpd") != 0) { 6253125Sjacobs uri_free(uri); 6263125Sjacobs return (0); 6273125Sjacobs } 6283125Sjacobs 6293125Sjacobs /* is it the local host? */ 6303125Sjacobs sysinfo(SI_HOSTNAME, buf, sizeof (buf)); 6313125Sjacobs if ((strcasecmp(uri->host, "localhost") != 0) && 6323127Sjacobs (strcasecmp(uri->host, buf) != 0)) { 6333125Sjacobs uri_free(uri); 6343125Sjacobs return (0); 6353125Sjacobs } 6363125Sjacobs 6373125Sjacobs uri_free(uri); 6383125Sjacobs return (1); 6393125Sjacobs } 6403125Sjacobs 6413125Sjacobs 6422264Sjacobs /* 6432264Sjacobs * This is the entry point for this program. The program takes the 6442264Sjacobs * following options: 6452264Sjacobs * (none) 6462264Sjacobs */ 6472264Sjacobs int 6482264Sjacobs main(int ac, char *av[]) 6492264Sjacobs { 6502264Sjacobs papi_status_t status; 6512264Sjacobs papi_service_t svc = NULL; 6522264Sjacobs papi_encryption_t encryption = PAPI_ENCRYPT_NEVER; 6532264Sjacobs FILE *ifp = stdin, 6542264Sjacobs *ofp = stdout; 6552264Sjacobs int c; 6562264Sjacobs char buf[BUFSIZ], 6572264Sjacobs **args, 6583125Sjacobs *printer, 6593125Sjacobs *run_dir = "/var/run/in.lpd", 6603125Sjacobs *run_user = NULL; 6613125Sjacobs struct passwd *pw = NULL; 6622264Sjacobs 6633125Sjacobs (void) chdir("/tmp"); /* run in /tmp by default */ 6642264Sjacobs openlog("bsd-gw", LOG_PID, LOG_LPR); 6652264Sjacobs 6663125Sjacobs while ((c = getopt(ac, av, "Ed:u:")) != EOF) 6672264Sjacobs switch (c) { 6682264Sjacobs case 'E': 6692264Sjacobs encryption = PAPI_ENCRYPT_ALWAYS; 6702264Sjacobs break; 6713125Sjacobs case 'd': /* run where they tell you */ 6723125Sjacobs run_dir = optarg; 6733125Sjacobs break; 6743125Sjacobs case 'u': /* run as */ 6753125Sjacobs run_user = optarg; 6763125Sjacobs break; 6772264Sjacobs default: 6782264Sjacobs ; 6792264Sjacobs } 6802264Sjacobs 6813125Sjacobs if (run_user != NULL) /* get the requested user info */ 6823125Sjacobs pw = getpwnam(run_user); 6833127Sjacobs 6843125Sjacobs if (run_dir != NULL) { /* setup the run_dir */ 6853125Sjacobs (void) mkdir(run_dir, 0700); 6863125Sjacobs if (pw != NULL) 6873125Sjacobs (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 6883125Sjacobs } 6893125Sjacobs 6903125Sjacobs if (pw != NULL) { /* run as the requested user */ 6913127Sjacobs syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 6923125Sjacobs pw->pw_name, pw->pw_uid, pw->pw_gid); 6933125Sjacobs initgroups(pw->pw_name, pw->pw_gid); 6943125Sjacobs setgid(pw->pw_gid); 6953125Sjacobs setuid(pw->pw_uid); 6963125Sjacobs } 6973125Sjacobs 6983125Sjacobs if (run_dir != NULL) /* move to the run_dir */ 6993125Sjacobs if (chdir(run_dir) < 0) { 7003125Sjacobs syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 7013125Sjacobs exit(1); 7023125Sjacobs } 7033125Sjacobs 7043125Sjacobs syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 7053125Sjacobs 7062264Sjacobs if (fgets(buf, sizeof (buf), ifp) == NULL) { 7072264Sjacobs if (feof(ifp) == 0) 7082264Sjacobs syslog(LOG_ERR, "Error reading from connection: %s", 7092264Sjacobs strerror(errno)); 7102264Sjacobs exit(1); 7112264Sjacobs } 7122264Sjacobs 7133125Sjacobs syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 7143125Sjacobs 7153125Sjacobs #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 7163125Sjacobs if ((buf[0] > '0') && (buf[0] < '6')) 7173125Sjacobs buf[0] -= '0'; 7183125Sjacobs #endif 7193125Sjacobs 7202264Sjacobs if ((buf[0] < 1) || (buf[0] > 5)) { 7212264Sjacobs fatal(ofp, "Invalid protocol request (%d): %c%s\n", 7222264Sjacobs buf[0], buf[0], buf); 7232264Sjacobs exit(1); 7242264Sjacobs } 7252264Sjacobs 7262264Sjacobs args = strsplit(&buf[1], "\t\n "); 7272264Sjacobs printer = *args++; 7282264Sjacobs 7292264Sjacobs if (printer == NULL) { 7302264Sjacobs fatal(ofp, "Can't determine requested printer"); 7312264Sjacobs exit(1); 7322264Sjacobs } 7332264Sjacobs 7343125Sjacobs if (cyclical_service_check(printer) != 0) { 7353125Sjacobs fatal(ofp, "%s is cyclical\n", printer); 7363125Sjacobs exit(1); 7373125Sjacobs } 7383125Sjacobs 7392264Sjacobs status = papiServiceCreate(&svc, printer, NULL, NULL, NULL, 7402264Sjacobs encryption, NULL); 7412264Sjacobs if (status != PAPI_OK) { 7422264Sjacobs fatal(ofp, "Failed to contact service for %s: %s\n", printer, 7432264Sjacobs verbose_papi_message(svc, status)); 7442264Sjacobs exit(1); 7452264Sjacobs } 7462264Sjacobs 7473125Sjacobs /* 7483125Sjacobs * Trusted Solaris can't be trusting of intermediaries. Pass 7493125Sjacobs * the socket connection to the print service to retrieve the 7503125Sjacobs * sensativity label off of a multi-level port. 7513125Sjacobs */ 7523125Sjacobs (void) papiServiceSetPeer(svc, fileno(ifp)); 7532264Sjacobs 7542264Sjacobs switch (buf[0]) { 7552264Sjacobs case '\1': /* restart printer */ 7562264Sjacobs ACK(ofp); /* there is no equivalent */ 7572264Sjacobs break; 7582264Sjacobs case '\2': /* transfer job(s) */ 7593125Sjacobs status = berkeley_transfer_files(svc, ifp, ofp, printer); 7602264Sjacobs break; 7612264Sjacobs case '\3': /* show queue (short) */ 7622264Sjacobs case '\4': { /* show queue (long) */ 7632264Sjacobs int count; 7642264Sjacobs 7652264Sjacobs for (count = 0; args[count] != 0; count++); 7662264Sjacobs 7672264Sjacobs berkeley_queue_report(svc, ofp, printer, buf[0], count, args); 7682264Sjacobs } 7692264Sjacobs break; 7702264Sjacobs case '\5': { /* cancel job(s) */ 7713125Sjacobs char *user = *args++; 7723125Sjacobs char *host = remote_host_name(ifp); 7732264Sjacobs int count; 7742264Sjacobs 7753125Sjacobs if (host != NULL) { 7763125Sjacobs char buf[BUFSIZ]; 7773125Sjacobs 7783125Sjacobs snprintf(buf, sizeof (buf), "%s@%s", user, host); 7793125Sjacobs status = papiServiceSetUserName(svc, buf); 7803125Sjacobs } else 7813125Sjacobs status = papiServiceSetUserName(svc, user); 7823125Sjacobs 7832264Sjacobs for (count = 0; args[count] != 0; count++); 7842264Sjacobs 7852264Sjacobs berkeley_cancel_request(svc, ofp, printer, count, args); 7862264Sjacobs } 7872264Sjacobs break; 7882264Sjacobs default: 7892264Sjacobs fatal(ofp, "unsupported protocol request (%c), %s", 7902264Sjacobs buf[0], &buf[1]); 7912264Sjacobs } 7922264Sjacobs 7932264Sjacobs (void) fflush(ofp); 7942264Sjacobs 7952264Sjacobs syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s", 7962264Sjacobs buf[0], printer, papiStatusString(status)); 7973125Sjacobs if (status != PAPI_OK) 7983125Sjacobs syslog(LOG_DEBUG, "detail: %s", 7993125Sjacobs verbose_papi_message(svc, status)); 8002264Sjacobs 8012264Sjacobs papiServiceDestroy(svc); 8022264Sjacobs 8032264Sjacobs return (0); 8042264Sjacobs } 805