1355b4669Sjacobs /* 2355b4669Sjacobs * CDDL HEADER START 3355b4669Sjacobs * 4355b4669Sjacobs * The contents of this file are subject to the terms of the 5355b4669Sjacobs * Common Development and Distribution License (the "License"). 6355b4669Sjacobs * You may not use this file except in compliance with the License. 7355b4669Sjacobs * 8355b4669Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9355b4669Sjacobs * or http://www.opensolaris.org/os/licensing. 10355b4669Sjacobs * See the License for the specific language governing permissions 11355b4669Sjacobs * and limitations under the License. 12355b4669Sjacobs * 13355b4669Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 14355b4669Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15355b4669Sjacobs * If applicable, add the following below this CDDL HEADER, with the 16355b4669Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 17355b4669Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 18355b4669Sjacobs * 19355b4669Sjacobs * CDDL HEADER END 20355b4669Sjacobs */ 21355b4669Sjacobs 22355b4669Sjacobs /* 23355b4669Sjacobs * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24355b4669Sjacobs * Use is subject to license terms. 25355b4669Sjacobs * 26355b4669Sjacobs */ 27355b4669Sjacobs 28355b4669Sjacobs /* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */ 29355b4669Sjacobs 30355b4669Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 31355b4669Sjacobs 32355b4669Sjacobs #include <stdio.h> 33355b4669Sjacobs #include <stdlib.h> 34*0a44ef6dSjacobs #include <unistd.h> 35*0a44ef6dSjacobs #include <fcntl.h> 36355b4669Sjacobs #include <stdarg.h> 37355b4669Sjacobs #include <string.h> 38355b4669Sjacobs #include <errno.h> 39355b4669Sjacobs #include <syslog.h> 40355b4669Sjacobs #include <libintl.h> 41*0a44ef6dSjacobs #include <pwd.h> 42*0a44ef6dSjacobs #include <grp.h> 43*0a44ef6dSjacobs #include <sys/types.h> 44*0a44ef6dSjacobs #include <sys/stat.h> 45*0a44ef6dSjacobs #include <sys/socket.h> 46*0a44ef6dSjacobs #include <netinet/in.h> 47*0a44ef6dSjacobs #include <arpa/inet.h> 48*0a44ef6dSjacobs #include <netdb.h> 49*0a44ef6dSjacobs #include <sys/systeminfo.h> 50355b4669Sjacobs 51355b4669Sjacobs #include <papi.h> 52*0a44ef6dSjacobs #include <uri.h> 53355b4669Sjacobs #include "common.h" 54355b4669Sjacobs 55355b4669Sjacobs #define ACK(fp) { (void) fputc('\0', fp); (void) fflush(fp); } 56355b4669Sjacobs #define NACK(fp) { (void) fputc('\1', fp); (void) fflush(fp); } 57355b4669Sjacobs 58355b4669Sjacobs /* 59355b4669Sjacobs * This file contains the front-end of the BSD Print Protocol adaptor. This 60355b4669Sjacobs * code assumes a BSD Socket interface to the networking side. 61355b4669Sjacobs */ 62355b4669Sjacobs 63*0a44ef6dSjacobs static char * 64*0a44ef6dSjacobs remote_host_name(FILE *fp) 65*0a44ef6dSjacobs { 66*0a44ef6dSjacobs struct hostent *hp; 67*0a44ef6dSjacobs struct sockaddr_in6 peer; 68*0a44ef6dSjacobs socklen_t peer_len = sizeof (peer); 69*0a44ef6dSjacobs int fd = fileno(fp); 70*0a44ef6dSjacobs int error_num; 71*0a44ef6dSjacobs char myname[MAXHOSTNAMELEN], tmp_buf[INET6_ADDRSTRLEN]; 72*0a44ef6dSjacobs char *hostname; 73*0a44ef6dSjacobs 74*0a44ef6dSjacobs /* who is our peer ? */ 75*0a44ef6dSjacobs if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) { 76*0a44ef6dSjacobs if ((errno != ENOTSOCK) && (errno != EINVAL)) 77*0a44ef6dSjacobs return (NULL); 78*0a44ef6dSjacobs else 79*0a44ef6dSjacobs return (strdup("localhost")); 80*0a44ef6dSjacobs } 81*0a44ef6dSjacobs 82*0a44ef6dSjacobs /* get their name or return a string containing their address */ 83*0a44ef6dSjacobs if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr, 84*0a44ef6dSjacobs sizeof (struct in6_addr), AF_INET6, 85*0a44ef6dSjacobs &error_num)) == NULL) { 86*0a44ef6dSjacobs return (strdup(inet_ntop(peer.sin6_family, 87*0a44ef6dSjacobs &peer.sin6_addr, tmp_buf, sizeof (tmp_buf)))); 88*0a44ef6dSjacobs } 89*0a44ef6dSjacobs 90*0a44ef6dSjacobs /* is it "localhost" ? */ 91*0a44ef6dSjacobs if (strcasecmp(hp->h_name, "localhost") == 0) 92*0a44ef6dSjacobs return (strdup("localhost")); 93*0a44ef6dSjacobs 94*0a44ef6dSjacobs /* duplicate the name because gethostbyXXXX() is not reentrant */ 95*0a44ef6dSjacobs hostname = strdup(hp->h_name); 96*0a44ef6dSjacobs (void) sysinfo(SI_HOSTNAME, myname, sizeof (myname)); 97*0a44ef6dSjacobs 98*0a44ef6dSjacobs /* is it from one of my addresses ? */ 99*0a44ef6dSjacobs if ((hp = getipnodebyname(myname, AF_INET6, AI_ALL|AI_V4MAPPED, 100*0a44ef6dSjacobs &error_num)) != NULL) { 101*0a44ef6dSjacobs struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list; 102*0a44ef6dSjacobs int i = 0; 103*0a44ef6dSjacobs 104*0a44ef6dSjacobs while (tmp[i] != NULL) { 105*0a44ef6dSjacobs if (memcmp(tmp[i++], &peer.sin6_addr, hp->h_length) 106*0a44ef6dSjacobs == 0) { 107*0a44ef6dSjacobs free(hostname); 108*0a44ef6dSjacobs return (strdup("localhost")); 109*0a44ef6dSjacobs } 110*0a44ef6dSjacobs } 111*0a44ef6dSjacobs } 112*0a44ef6dSjacobs 113*0a44ef6dSjacobs /* It must be someone else */ 114*0a44ef6dSjacobs return (hostname); 115*0a44ef6dSjacobs } 116*0a44ef6dSjacobs 117*0a44ef6dSjacobs static void 118355b4669Sjacobs fatal(FILE *fp, char *fmt, ...) 119355b4669Sjacobs { 120355b4669Sjacobs va_list ap; 121355b4669Sjacobs 122355b4669Sjacobs va_start(ap, fmt); 123355b4669Sjacobs vsyslog(LOG_DEBUG, fmt, ap); 124355b4669Sjacobs vfprintf(fp, fmt, ap); 125355b4669Sjacobs va_end(ap); 126*0a44ef6dSjacobs exit(1); 127355b4669Sjacobs } 128355b4669Sjacobs 129355b4669Sjacobs static void 130*0a44ef6dSjacobs cleanup(char ***files, char **cf) 131355b4669Sjacobs { 132*0a44ef6dSjacobs if (*files != NULL) { 133355b4669Sjacobs int i; 134355b4669Sjacobs 135*0a44ef6dSjacobs for (i = 0; (*files)[i] != NULL; i++) { 136*0a44ef6dSjacobs (void) unlink((*files)[i]); 137*0a44ef6dSjacobs free((*files)[i]); 138*0a44ef6dSjacobs } 139*0a44ef6dSjacobs free(*files); 140*0a44ef6dSjacobs *files = NULL; 141*0a44ef6dSjacobs } 142*0a44ef6dSjacobs 143*0a44ef6dSjacobs if (*cf != NULL) { 144*0a44ef6dSjacobs free(*cf); 145*0a44ef6dSjacobs *cf = NULL; 146355b4669Sjacobs } 147355b4669Sjacobs } 148355b4669Sjacobs 149*0a44ef6dSjacobs static papi_attribute_t ** 150*0a44ef6dSjacobs parse_cf(papi_service_t svc, char *cf, char **files) 151355b4669Sjacobs { 152*0a44ef6dSjacobs papi_attribute_t **list = NULL; 153*0a44ef6dSjacobs char previous = NULL, 154*0a44ef6dSjacobs *entry, 155*0a44ef6dSjacobs *s, 156*0a44ef6dSjacobs text[BUFSIZ]; 157*0a44ef6dSjacobs int count = 0, 158*0a44ef6dSjacobs copies_set = 0, 159*0a44ef6dSjacobs copies = 0; 160355b4669Sjacobs 161*0a44ef6dSjacobs for (entry = strtok(cf, "\n"); entry != NULL; 162*0a44ef6dSjacobs entry = strtok(NULL, "\n")) { 163*0a44ef6dSjacobs char *format = NULL; 164*0a44ef6dSjacobs 165*0a44ef6dSjacobs /* count the copies */ 166*0a44ef6dSjacobs if ((entry[0] >= 'a') && (entry[0] <= 'z') && 167*0a44ef6dSjacobs (copies_set == 0) && (previous == entry[0])) 168*0a44ef6dSjacobs copies++; 169*0a44ef6dSjacobs else if ((previous >= 'a') && (previous <= 'z')) 170*0a44ef6dSjacobs copies_set = 1; 171*0a44ef6dSjacobs previous = entry[0]; 172*0a44ef6dSjacobs 173*0a44ef6dSjacobs /* process the control message */ 174*0a44ef6dSjacobs switch (entry[0]) { 175*0a44ef6dSjacobs /* RFC-1179 options */ 176*0a44ef6dSjacobs case 'J': /* RFC-1179 Banner Job Name */ 177*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 178*0a44ef6dSjacobs "job-name", ++entry); 179*0a44ef6dSjacobs break; 180*0a44ef6dSjacobs case 'C': /* RFC-1179 Banner Class Name */ 181*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 182*0a44ef6dSjacobs "rfc-1179-class", ++entry); 183*0a44ef6dSjacobs break; 184*0a44ef6dSjacobs case 'L': /* RFC-1179 Banner toggle */ 185*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 186*0a44ef6dSjacobs "job-sheets", "standard"); 187*0a44ef6dSjacobs break; 188*0a44ef6dSjacobs case 'T': /* RFC-1179 Title (pr) */ 189*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 190*0a44ef6dSjacobs "pr-title", ++entry); 191*0a44ef6dSjacobs break; 192*0a44ef6dSjacobs case 'H': /* RFC-1179 Host */ 193*0a44ef6dSjacobs /* 194*0a44ef6dSjacobs * use the host as known by us, not by them 195*0a44ef6dSjacobs * 196*0a44ef6dSjacobs * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 197*0a44ef6dSjacobs * "job-originating-host-name", ++entry); 198*0a44ef6dSjacobs */ 199*0a44ef6dSjacobs break; 200*0a44ef6dSjacobs case 'P': /* RFC-1179 User */ 201*0a44ef6dSjacobs ++entry; 202*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 203*0a44ef6dSjacobs "requesting-user-name", entry); 204*0a44ef6dSjacobs papiServiceSetUserName(svc, entry); 205*0a44ef6dSjacobs break; 206*0a44ef6dSjacobs case 'M': /* RFC-1179 Mail to User */ 207*0a44ef6dSjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 208*0a44ef6dSjacobs "rfc-1179-mail", 1); 209*0a44ef6dSjacobs break; 210*0a44ef6dSjacobs case 'W': /* RFC-1179 Width (pr) */ 211*0a44ef6dSjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 212*0a44ef6dSjacobs "pr-width", atoi(++entry)); 213*0a44ef6dSjacobs break; 214*0a44ef6dSjacobs case 'I': /* RFC-1179 Indent (pr) */ 215*0a44ef6dSjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 216*0a44ef6dSjacobs "pr-indent", atoi(++entry)); 217*0a44ef6dSjacobs break; 218*0a44ef6dSjacobs case 'N': /* RFC-1179 Filename */ 219*0a44ef6dSjacobs /* could have HPUX extension embedded */ 220*0a44ef6dSjacobs if (entry[1] != ' ') { /* real pathname */ 221*0a44ef6dSjacobs #ifdef DEBUG 222*0a44ef6dSjacobs papiAttributeListAddString(&list, 223*0a44ef6dSjacobs PAPI_ATTR_EXCL, 224*0a44ef6dSjacobs "flist", ++entry); 225*0a44ef6dSjacobs #endif 226*0a44ef6dSjacobs } else if (entry[2] == 'O') /* HPUX lp -o options */ 227*0a44ef6dSjacobs papiAttributeListFromString(&list, 228*0a44ef6dSjacobs PAPI_ATTR_APPEND, ++entry); 229*0a44ef6dSjacobs break; 230*0a44ef6dSjacobs case 'U': /* RFC-1179 Unlink */ 231*0a44ef6dSjacobs break; /* ignored */ 232*0a44ef6dSjacobs case '1': /* RFC-1179 TROFF Font R */ 233*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 234*0a44ef6dSjacobs "rfc-1179-font-r", ++entry); 235*0a44ef6dSjacobs break; 236*0a44ef6dSjacobs case '2': /* RFC-1179 TROFF Font I */ 237*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 238*0a44ef6dSjacobs "rfc-1179-font-i", ++entry); 239*0a44ef6dSjacobs break; 240*0a44ef6dSjacobs case '3': /* RFC-1179 TROFF Font B */ 241*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 242*0a44ef6dSjacobs "rfc-1179-font-b", ++entry); 243*0a44ef6dSjacobs break; 244*0a44ef6dSjacobs case '4': /* RFC-1179 TROFF Font S */ 245*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 246*0a44ef6dSjacobs "rfc-1179-font-s", ++entry); 247*0a44ef6dSjacobs break; 248*0a44ef6dSjacobs case 'f': /* RFC-1179 ASCII file (print) */ 249*0a44ef6dSjacobs format = "text/plain"; 250*0a44ef6dSjacobs if (is_postscript(files[0]) == 1) 251*0a44ef6dSjacobs format = "application/postscript"; 252*0a44ef6dSjacobs break; 253*0a44ef6dSjacobs case 'l': /* RFC-1179 CATV file (print) */ 254*0a44ef6dSjacobs format = "application/octet-stream"; 255*0a44ef6dSjacobs if (is_postscript(files[0]) == 1) 256*0a44ef6dSjacobs format = "application/postscript"; 257*0a44ef6dSjacobs break; 258*0a44ef6dSjacobs case 'o': /* RFC-1179 Postscript file (print) */ 259*0a44ef6dSjacobs format = "application/postscript"; 260*0a44ef6dSjacobs break; 261*0a44ef6dSjacobs case 'p': /* RFC-1179 PR file (print) */ 262*0a44ef6dSjacobs format = "application/x-pr"; 263*0a44ef6dSjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 264*0a44ef6dSjacobs "pr-filter", 1); 265*0a44ef6dSjacobs break; 266*0a44ef6dSjacobs case 't': /* RFC-1179 TROFF file (print) */ 267*0a44ef6dSjacobs format = "application/x-troff"; 268*0a44ef6dSjacobs break; 269*0a44ef6dSjacobs case 'n': /* RFC-1179 DITROFF file (print) */ 270*0a44ef6dSjacobs format = "application/x-ditroff"; 271*0a44ef6dSjacobs break; 272*0a44ef6dSjacobs case 'd': /* RFC-1179 DVI file (print) */ 273*0a44ef6dSjacobs format = "application/x-dvi"; 274*0a44ef6dSjacobs break; 275*0a44ef6dSjacobs case 'g': /* RFC-1179 GRAPH file (print) */ 276*0a44ef6dSjacobs format = "application/x-plot"; 277*0a44ef6dSjacobs break; 278*0a44ef6dSjacobs case 'c': /* RFC-1179 CIF file (print) */ 279*0a44ef6dSjacobs format = "application/x-cif"; 280*0a44ef6dSjacobs break; 281*0a44ef6dSjacobs case 'v': /* RFC-1179 RASTER file (print) */ 282*0a44ef6dSjacobs format = "application/x-raster"; 283*0a44ef6dSjacobs break; 284*0a44ef6dSjacobs case 'r': /* RFC-1179 FORTRAN file (print) */ 285*0a44ef6dSjacobs format = "application/x-fortran"; 286*0a44ef6dSjacobs break; 287*0a44ef6dSjacobs /* Sun Solaris Extensions */ 288*0a44ef6dSjacobs case 'O': 289*0a44ef6dSjacobs ++entry; 290*0a44ef6dSjacobs do { 291*0a44ef6dSjacobs if (*entry != '"') 292*0a44ef6dSjacobs text[count++] = *entry; 293*0a44ef6dSjacobs } while (*entry++); 294*0a44ef6dSjacobs papiAttributeListFromString(&list, PAPI_ATTR_APPEND, 295*0a44ef6dSjacobs text); 296*0a44ef6dSjacobs break; 297*0a44ef6dSjacobs case '5': 298*0a44ef6dSjacobs ++entry; 299*0a44ef6dSjacobs switch (entry[0]) { 300*0a44ef6dSjacobs case 'f': /* Solaris form */ 301*0a44ef6dSjacobs papiAttributeListAddString(&list, 302*0a44ef6dSjacobs PAPI_ATTR_EXCL, 303*0a44ef6dSjacobs "form", ++entry); 304*0a44ef6dSjacobs break; 305*0a44ef6dSjacobs case 'H': /* Solaris handling */ 306*0a44ef6dSjacobs ++entry; 307*0a44ef6dSjacobs if (strcasecmp(entry, "hold") == 0) 308*0a44ef6dSjacobs papiAttributeListAddString(&list, 309*0a44ef6dSjacobs PAPI_ATTR_EXCL, 310*0a44ef6dSjacobs "job-hold-until", "indefinite"); 311*0a44ef6dSjacobs else if (strcasecmp(entry, "release") == 0) 312*0a44ef6dSjacobs papiAttributeListAddString(&list, 313*0a44ef6dSjacobs PAPI_ATTR_EXCL, 314*0a44ef6dSjacobs "job-hold-until", "no-hold"); 315*0a44ef6dSjacobs else if (strcasecmp(entry, "immediate") == 0) 316*0a44ef6dSjacobs papiAttributeListAddInteger(&list, 317*0a44ef6dSjacobs PAPI_ATTR_EXCL, 318*0a44ef6dSjacobs "job-priority", 100); 319*0a44ef6dSjacobs else 320*0a44ef6dSjacobs papiAttributeListAddString(&list, 321*0a44ef6dSjacobs PAPI_ATTR_EXCL, 322*0a44ef6dSjacobs "job-hold-until", entry); 323*0a44ef6dSjacobs break; 324*0a44ef6dSjacobs case 'p': /* Solaris notification */ 325*0a44ef6dSjacobs papiAttributeListAddBoolean(&list, 326*0a44ef6dSjacobs PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 327*0a44ef6dSjacobs break; 328*0a44ef6dSjacobs case 'P': /* Solaris page list */ 329*0a44ef6dSjacobs papiAttributeListAddString(&list, 330*0a44ef6dSjacobs PAPI_ATTR_EXCL, 331*0a44ef6dSjacobs "page-ranges", ++entry); 332*0a44ef6dSjacobs break; 333*0a44ef6dSjacobs case 'q': { /* Solaris priority */ 334*0a44ef6dSjacobs int i = atoi(optarg); 335*0a44ef6dSjacobs 336*0a44ef6dSjacobs i = 99 * (39 - i) / 39 + 1; 337*0a44ef6dSjacobs if ((i < 1) || (i > 100)) 338*0a44ef6dSjacobs i = 50; 339*0a44ef6dSjacobs papiAttributeListAddInteger(&list, 340*0a44ef6dSjacobs PAPI_ATTR_EXCL, "priority", i); 341*0a44ef6dSjacobs } 342*0a44ef6dSjacobs break; 343*0a44ef6dSjacobs case 'S': /* Solaris character set */ 344*0a44ef6dSjacobs papiAttributeListAddString(&list, 345*0a44ef6dSjacobs PAPI_ATTR_EXCL, "lp-charset", 346*0a44ef6dSjacobs ++entry); 347*0a44ef6dSjacobs break; 348*0a44ef6dSjacobs case 'T': /* Solaris type */ 349*0a44ef6dSjacobs format = lp_type_to_mime_type(++entry); 350*0a44ef6dSjacobs break; 351*0a44ef6dSjacobs case 'y': /* Solaris mode */ 352*0a44ef6dSjacobs papiAttributeListAddString(&list, 353*0a44ef6dSjacobs PAPI_ATTR_APPEND, "lp-modes", ++entry); 354*0a44ef6dSjacobs break; 355*0a44ef6dSjacobs default: 356*0a44ef6dSjacobs syslog(LOG_INFO|LOG_DEBUG, 357*0a44ef6dSjacobs "Warning: cf message (%s) ignored", 358*0a44ef6dSjacobs entry); 359*0a44ef6dSjacobs break; 360*0a44ef6dSjacobs } 361*0a44ef6dSjacobs break; 362*0a44ef6dSjacobs /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 363*0a44ef6dSjacobs 364*0a44ef6dSjacobs default: 365*0a44ef6dSjacobs syslog(LOG_INFO|LOG_DEBUG, 366*0a44ef6dSjacobs "Warning: cf message (%s) ignored", entry); 367*0a44ef6dSjacobs break; 368*0a44ef6dSjacobs } 369*0a44ef6dSjacobs 370*0a44ef6dSjacobs if (format != NULL) 371*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 372*0a44ef6dSjacobs "document-format", format); 373*0a44ef6dSjacobs } 374*0a44ef6dSjacobs 375*0a44ef6dSjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 376*0a44ef6dSjacobs "copies", ++copies); 377*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 378*0a44ef6dSjacobs "job-sheets", "none"); 379*0a44ef6dSjacobs 380*0a44ef6dSjacobs return (list); 381*0a44ef6dSjacobs } 382*0a44ef6dSjacobs 383*0a44ef6dSjacobs static papi_status_t 384*0a44ef6dSjacobs submit_job(papi_service_t svc, FILE *ifp, char *printer, char *cf, char **files) 385*0a44ef6dSjacobs { 386*0a44ef6dSjacobs papi_attribute_t **list = NULL; 387*0a44ef6dSjacobs papi_status_t status; 388*0a44ef6dSjacobs papi_job_t job = NULL; 389*0a44ef6dSjacobs char *format = ""; 390*0a44ef6dSjacobs 391*0a44ef6dSjacobs if ((list = parse_cf(svc, cf, files)) != NULL) { 392*0a44ef6dSjacobs /* use the host as known by us, not by them */ 393*0a44ef6dSjacobs char *host = remote_host_name(ifp); 394*0a44ef6dSjacobs 395*0a44ef6dSjacobs if (host != NULL) { 396*0a44ef6dSjacobs papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 397*0a44ef6dSjacobs "job-originating-host-name", host); 398*0a44ef6dSjacobs free(host); 399*0a44ef6dSjacobs } 400*0a44ef6dSjacobs } 401*0a44ef6dSjacobs 402*0a44ef6dSjacobs status = papiJobSubmit(svc, printer, list, NULL, files, &job); 403*0a44ef6dSjacobs syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 404*0a44ef6dSjacobs if (status != PAPI_OK) { 405*0a44ef6dSjacobs char *tmp = papiServiceGetStatusMessage(svc); 406*0a44ef6dSjacobs 407*0a44ef6dSjacobs syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 408*0a44ef6dSjacobs } 409*0a44ef6dSjacobs papiJobFree(job); 410*0a44ef6dSjacobs 411*0a44ef6dSjacobs return (status); 412*0a44ef6dSjacobs } 413*0a44ef6dSjacobs 414*0a44ef6dSjacobs static char * 415*0a44ef6dSjacobs receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 416*0a44ef6dSjacobs { 417*0a44ef6dSjacobs char *ptr, *cf_data; 418*0a44ef6dSjacobs 419*0a44ef6dSjacobs if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 420*0a44ef6dSjacobs NACK(ofp); 421*0a44ef6dSjacobs return (NULL); 422*0a44ef6dSjacobs } else 423355b4669Sjacobs ACK(ofp); 424355b4669Sjacobs 425*0a44ef6dSjacobs while (size > 0) { 426*0a44ef6dSjacobs int rc; 427355b4669Sjacobs 428*0a44ef6dSjacobs if (((rc = fread(ptr, 1, size, ifp)) == 0) && 429*0a44ef6dSjacobs (feof(ifp) != 0)) { 430*0a44ef6dSjacobs free(cf_data); 431*0a44ef6dSjacobs return (NULL); 432*0a44ef6dSjacobs } else { 433*0a44ef6dSjacobs ptr += rc; 434*0a44ef6dSjacobs size -= rc; 435*0a44ef6dSjacobs } 436*0a44ef6dSjacobs } 437*0a44ef6dSjacobs syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 438*0a44ef6dSjacobs 439*0a44ef6dSjacobs if (fgetc(ifp) != 0) { 440*0a44ef6dSjacobs free(cf_data); 441*0a44ef6dSjacobs return (NULL); 442*0a44ef6dSjacobs } 443*0a44ef6dSjacobs ACK(ofp); 444*0a44ef6dSjacobs 445*0a44ef6dSjacobs return (cf_data); 446*0a44ef6dSjacobs } 447*0a44ef6dSjacobs 448*0a44ef6dSjacobs static char * 449*0a44ef6dSjacobs receive_data_file(FILE *ifp, FILE *ofp, int size) 450*0a44ef6dSjacobs { 451355b4669Sjacobs char file[] = "lpdXXXXXX"; 452*0a44ef6dSjacobs char buf[BUFSIZ]; 453355b4669Sjacobs int fd; 454355b4669Sjacobs 455*0a44ef6dSjacobs if ((fd = mkstemp(file)) < 0) { 456*0a44ef6dSjacobs NACK(ofp); 457*0a44ef6dSjacobs return (NULL); 458*0a44ef6dSjacobs } else 459*0a44ef6dSjacobs ACK(ofp); 460355b4669Sjacobs 461*0a44ef6dSjacobs while (size > 0) { 462*0a44ef6dSjacobs int rc = ((size > BUFSIZ) ? BUFSIZ : size); 463*0a44ef6dSjacobs 464*0a44ef6dSjacobs if (((rc = fread(buf, 1, rc, ifp)) == 0) && 465*0a44ef6dSjacobs (feof(ifp) != 0)) { 466*0a44ef6dSjacobs close(fd); 467*0a44ef6dSjacobs unlink(file); 468*0a44ef6dSjacobs return (NULL); 469*0a44ef6dSjacobs } else { 470*0a44ef6dSjacobs char *ptr = buf; 471*0a44ef6dSjacobs 472*0a44ef6dSjacobs while (rc > 0) { 473*0a44ef6dSjacobs int wrc = write(fd, ptr, rc); 474*0a44ef6dSjacobs 475*0a44ef6dSjacobs if (wrc < 0) { 476*0a44ef6dSjacobs close(fd); 477*0a44ef6dSjacobs unlink(file); 478*0a44ef6dSjacobs return(NULL); 479*0a44ef6dSjacobs } 480*0a44ef6dSjacobs 481*0a44ef6dSjacobs ptr += wrc; 482*0a44ef6dSjacobs size -= wrc; 483*0a44ef6dSjacobs rc -= wrc; 484*0a44ef6dSjacobs } 485*0a44ef6dSjacobs } 486*0a44ef6dSjacobs } 487*0a44ef6dSjacobs close(fd); 488*0a44ef6dSjacobs if (fgetc(ifp) != 0) { 489*0a44ef6dSjacobs unlink(file); 490*0a44ef6dSjacobs return (NULL); 491*0a44ef6dSjacobs } 492*0a44ef6dSjacobs ACK(ofp); 493*0a44ef6dSjacobs 494*0a44ef6dSjacobs return (strdup(file)); 495*0a44ef6dSjacobs } 496*0a44ef6dSjacobs 497*0a44ef6dSjacobs static papi_status_t 498*0a44ef6dSjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 499*0a44ef6dSjacobs { 500*0a44ef6dSjacobs papi_status_t status = PAPI_OK; 501*0a44ef6dSjacobs char *file, **files = NULL; /* the job data files */ 502*0a44ef6dSjacobs char *cf = NULL; 503*0a44ef6dSjacobs char buf[BUFSIZ]; 504*0a44ef6dSjacobs 505*0a44ef6dSjacobs while (fgets(buf, sizeof (buf), ifp) != NULL) { 506*0a44ef6dSjacobs int size; 507*0a44ef6dSjacobs 508*0a44ef6dSjacobs syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 509*0a44ef6dSjacobs #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 510*0a44ef6dSjacobs if ((buf[0] > '0') && (buf[0] < '4')) 511*0a44ef6dSjacobs buf[0] -= '0'; 512*0a44ef6dSjacobs #endif 513*0a44ef6dSjacobs switch (buf[0]) { 514*0a44ef6dSjacobs case 0x01: /* Abort */ 515*0a44ef6dSjacobs cleanup(&files, &cf); 516*0a44ef6dSjacobs break; 517*0a44ef6dSjacobs case 0x02: { /* Receive control file */ 518*0a44ef6dSjacobs cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1])); 519*0a44ef6dSjacobs if (cf == NULL) { 520*0a44ef6dSjacobs cleanup(&files, &cf); 521*0a44ef6dSjacobs return (PAPI_BAD_REQUEST); 522*0a44ef6dSjacobs } else if (files != NULL) { 523*0a44ef6dSjacobs status = submit_job(svc, ifp, printer, cf, 524*0a44ef6dSjacobs files); 525*0a44ef6dSjacobs cleanup(&files, &cf); 526*0a44ef6dSjacobs } 527*0a44ef6dSjacobs } 528*0a44ef6dSjacobs break; 529*0a44ef6dSjacobs case 0x03: { /* Receive data file */ 530*0a44ef6dSjacobs file = receive_data_file(ifp, ofp, atoi(&buf[1])); 531*0a44ef6dSjacobs if (file == NULL) { 532*0a44ef6dSjacobs cleanup(&files, &cf); 533*0a44ef6dSjacobs return (PAPI_TEMPORARY_ERROR); 534*0a44ef6dSjacobs } 535*0a44ef6dSjacobs list_append(&files, file); 536355b4669Sjacobs } 537355b4669Sjacobs break; 538355b4669Sjacobs default: 539*0a44ef6dSjacobs cleanup(&files, &cf); 540355b4669Sjacobs fatal(ofp, "protocol screwup"); 541355b4669Sjacobs break; 542355b4669Sjacobs } 543355b4669Sjacobs } 544355b4669Sjacobs 545*0a44ef6dSjacobs if ((cf != NULL) && (files != NULL)) 546*0a44ef6dSjacobs status = submit_job(svc, ifp, printer, cf, files); 547*0a44ef6dSjacobs 548*0a44ef6dSjacobs cleanup(&files, &cf); 549*0a44ef6dSjacobs 550*0a44ef6dSjacobs return (status); 551355b4669Sjacobs } 552355b4669Sjacobs 553*0a44ef6dSjacobs static papi_status_t 554355b4669Sjacobs berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp, 555355b4669Sjacobs char *printer) 556355b4669Sjacobs { 557355b4669Sjacobs papi_status_t status; 558355b4669Sjacobs papi_printer_t p = NULL; 559*0a44ef6dSjacobs char *keys[] = { "printer-is-accepting-jobs", NULL }; 560355b4669Sjacobs 561355b4669Sjacobs status = papiPrinterQuery(svc, printer, keys, NULL, &p); 562355b4669Sjacobs if ((status == PAPI_OK) && (p != NULL)) { 563355b4669Sjacobs papi_attribute_t **attrs = papiPrinterGetAttributeList(p); 564355b4669Sjacobs char accepting = PAPI_FALSE; 565355b4669Sjacobs 566355b4669Sjacobs papiAttributeListGetBoolean(attrs, NULL, 567*0a44ef6dSjacobs "printer-is-accepting-jobs", &accepting); 568355b4669Sjacobs 569*0a44ef6dSjacobs if (accepting == PAPI_TRUE) { 570*0a44ef6dSjacobs ACK(ofp); 571*0a44ef6dSjacobs status = berkeley_receive_files(svc, ifp, ofp, printer); 572*0a44ef6dSjacobs } else 573355b4669Sjacobs NACK(ofp); 574355b4669Sjacobs 575355b4669Sjacobs papiPrinterFree(p); 576355b4669Sjacobs } else 577355b4669Sjacobs NACK(ofp); 578*0a44ef6dSjacobs 579*0a44ef6dSjacobs return (status); 580355b4669Sjacobs } 581355b4669Sjacobs 582*0a44ef6dSjacobs static int 583*0a44ef6dSjacobs cyclical_service_check(char *svc_name) 584*0a44ef6dSjacobs { 585*0a44ef6dSjacobs papi_attribute_t **list; 586*0a44ef6dSjacobs char buf[BUFSIZ]; 587*0a44ef6dSjacobs uri_t *uri = NULL; 588*0a44ef6dSjacobs char *s = NULL; 589*0a44ef6dSjacobs 590*0a44ef6dSjacobs /* was there a printer? */ 591*0a44ef6dSjacobs if (svc_name == NULL) 592*0a44ef6dSjacobs return (0); 593*0a44ef6dSjacobs 594*0a44ef6dSjacobs if ((list = getprinterbyname(svc_name, NULL)) == NULL) 595*0a44ef6dSjacobs return (0); /* if it doesnt' resolve, we will fail later */ 596*0a44ef6dSjacobs 597*0a44ef6dSjacobs papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 598*0a44ef6dSjacobs if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 599*0a44ef6dSjacobs return (0); /* they don't match */ 600*0a44ef6dSjacobs 601*0a44ef6dSjacobs /* is it in uri form? */ 602*0a44ef6dSjacobs if (uri_from_string(s, &uri) < 0) 603*0a44ef6dSjacobs return (0); 604*0a44ef6dSjacobs 605*0a44ef6dSjacobs if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 606*0a44ef6dSjacobs uri_free(uri); 607*0a44ef6dSjacobs return (0); 608*0a44ef6dSjacobs } 609*0a44ef6dSjacobs 610*0a44ef6dSjacobs /* is it in lpd form? */ 611*0a44ef6dSjacobs if (strcasecmp(uri->scheme, "lpd") != 0) { 612*0a44ef6dSjacobs uri_free(uri); 613*0a44ef6dSjacobs return (0); 614*0a44ef6dSjacobs } 615*0a44ef6dSjacobs 616*0a44ef6dSjacobs /* is it the local host? */ 617*0a44ef6dSjacobs sysinfo(SI_HOSTNAME, buf, sizeof (buf)); 618*0a44ef6dSjacobs if ((strcasecmp(uri->host, "localhost") != 0) && 619*0a44ef6dSjacobs (strcasecmp(uri->host, buf) != 0)) { 620*0a44ef6dSjacobs uri_free(uri); 621*0a44ef6dSjacobs return (0); 622*0a44ef6dSjacobs } 623*0a44ef6dSjacobs 624*0a44ef6dSjacobs uri_free(uri); 625*0a44ef6dSjacobs return (1); 626*0a44ef6dSjacobs } 627*0a44ef6dSjacobs 628*0a44ef6dSjacobs 629355b4669Sjacobs /* 630355b4669Sjacobs * This is the entry point for this program. The program takes the 631355b4669Sjacobs * following options: 632355b4669Sjacobs * (none) 633355b4669Sjacobs */ 634355b4669Sjacobs int 635355b4669Sjacobs main(int ac, char *av[]) 636355b4669Sjacobs { 637355b4669Sjacobs papi_status_t status; 638355b4669Sjacobs papi_service_t svc = NULL; 639355b4669Sjacobs papi_encryption_t encryption = PAPI_ENCRYPT_NEVER; 640355b4669Sjacobs FILE *ifp = stdin, 641355b4669Sjacobs *ofp = stdout; 642355b4669Sjacobs int c; 643355b4669Sjacobs char buf[BUFSIZ], 644355b4669Sjacobs **args, 645*0a44ef6dSjacobs *printer, 646*0a44ef6dSjacobs *run_dir = "/var/run/in.lpd", 647*0a44ef6dSjacobs *run_user = NULL; 648*0a44ef6dSjacobs struct passwd *pw = NULL; 649355b4669Sjacobs 650*0a44ef6dSjacobs (void) chdir("/tmp"); /* run in /tmp by default */ 651355b4669Sjacobs openlog("bsd-gw", LOG_PID, LOG_LPR); 652355b4669Sjacobs 653*0a44ef6dSjacobs while ((c = getopt(ac, av, "Ed:u:")) != EOF) 654355b4669Sjacobs switch (c) { 655355b4669Sjacobs case 'E': 656355b4669Sjacobs encryption = PAPI_ENCRYPT_ALWAYS; 657355b4669Sjacobs break; 658*0a44ef6dSjacobs case 'd': /* run where they tell you */ 659*0a44ef6dSjacobs run_dir = optarg; 660*0a44ef6dSjacobs break; 661*0a44ef6dSjacobs case 'u': /* run as */ 662*0a44ef6dSjacobs run_user = optarg; 663*0a44ef6dSjacobs break; 664355b4669Sjacobs default: 665355b4669Sjacobs ; 666355b4669Sjacobs } 667355b4669Sjacobs 668*0a44ef6dSjacobs if (run_user != NULL) /* get the requested user info */ 669*0a44ef6dSjacobs pw = getpwnam(run_user); 670*0a44ef6dSjacobs 671*0a44ef6dSjacobs if (run_dir != NULL) { /* setup the run_dir */ 672*0a44ef6dSjacobs (void) mkdir(run_dir, 0700); 673*0a44ef6dSjacobs if (pw != NULL) 674*0a44ef6dSjacobs (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 675*0a44ef6dSjacobs } 676*0a44ef6dSjacobs 677*0a44ef6dSjacobs if (pw != NULL) { /* run as the requested user */ 678*0a44ef6dSjacobs syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 679*0a44ef6dSjacobs pw->pw_name, pw->pw_uid, pw->pw_gid); 680*0a44ef6dSjacobs initgroups(pw->pw_name, pw->pw_gid); 681*0a44ef6dSjacobs setgid(pw->pw_gid); 682*0a44ef6dSjacobs setuid(pw->pw_uid); 683*0a44ef6dSjacobs } 684*0a44ef6dSjacobs 685*0a44ef6dSjacobs if (run_dir != NULL) /* move to the run_dir */ 686*0a44ef6dSjacobs if (chdir(run_dir) < 0) { 687*0a44ef6dSjacobs syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 688*0a44ef6dSjacobs exit(1); 689*0a44ef6dSjacobs } 690*0a44ef6dSjacobs 691*0a44ef6dSjacobs syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 692*0a44ef6dSjacobs 693355b4669Sjacobs if (fgets(buf, sizeof (buf), ifp) == NULL) { 694355b4669Sjacobs if (feof(ifp) == 0) 695355b4669Sjacobs syslog(LOG_ERR, "Error reading from connection: %s", 696355b4669Sjacobs strerror(errno)); 697355b4669Sjacobs exit(1); 698355b4669Sjacobs } 699355b4669Sjacobs 700*0a44ef6dSjacobs syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 701*0a44ef6dSjacobs 702*0a44ef6dSjacobs #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 703*0a44ef6dSjacobs if ((buf[0] > '0') && (buf[0] < '6')) 704*0a44ef6dSjacobs buf[0] -= '0'; 705*0a44ef6dSjacobs #endif 706*0a44ef6dSjacobs 707355b4669Sjacobs if ((buf[0] < 1) || (buf[0] > 5)) { 708355b4669Sjacobs fatal(ofp, "Invalid protocol request (%d): %c%s\n", 709355b4669Sjacobs buf[0], buf[0], buf); 710355b4669Sjacobs exit(1); 711355b4669Sjacobs } 712355b4669Sjacobs 713355b4669Sjacobs args = strsplit(&buf[1], "\t\n "); 714355b4669Sjacobs printer = *args++; 715355b4669Sjacobs 716355b4669Sjacobs if (printer == NULL) { 717355b4669Sjacobs fatal(ofp, "Can't determine requested printer"); 718355b4669Sjacobs exit(1); 719355b4669Sjacobs } 720355b4669Sjacobs 721*0a44ef6dSjacobs if (cyclical_service_check(printer) != 0) { 722*0a44ef6dSjacobs fatal(ofp, "%s is cyclical\n", printer); 723*0a44ef6dSjacobs exit(1); 724*0a44ef6dSjacobs } 725*0a44ef6dSjacobs 726355b4669Sjacobs status = papiServiceCreate(&svc, printer, NULL, NULL, NULL, 727355b4669Sjacobs encryption, NULL); 728355b4669Sjacobs if (status != PAPI_OK) { 729355b4669Sjacobs fatal(ofp, "Failed to contact service for %s: %s\n", printer, 730355b4669Sjacobs verbose_papi_message(svc, status)); 731355b4669Sjacobs exit(1); 732355b4669Sjacobs } 733355b4669Sjacobs 734*0a44ef6dSjacobs /* 735*0a44ef6dSjacobs * Trusted Solaris can't be trusting of intermediaries. Pass 736*0a44ef6dSjacobs * the socket connection to the print service to retrieve the 737*0a44ef6dSjacobs * sensativity label off of a multi-level port. 738*0a44ef6dSjacobs */ 739*0a44ef6dSjacobs (void) papiServiceSetPeer(svc, fileno(ifp)); 740355b4669Sjacobs 741355b4669Sjacobs switch (buf[0]) { 742355b4669Sjacobs case '\1': /* restart printer */ 743355b4669Sjacobs ACK(ofp); /* there is no equivalent */ 744355b4669Sjacobs break; 745355b4669Sjacobs case '\2': /* transfer job(s) */ 746*0a44ef6dSjacobs status = berkeley_transfer_files(svc, ifp, ofp, printer); 747355b4669Sjacobs break; 748355b4669Sjacobs case '\3': /* show queue (short) */ 749355b4669Sjacobs case '\4': { /* show queue (long) */ 750355b4669Sjacobs int count; 751355b4669Sjacobs 752355b4669Sjacobs for (count = 0; args[count] != 0; count++); 753355b4669Sjacobs 754355b4669Sjacobs berkeley_queue_report(svc, ofp, printer, buf[0], count, args); 755355b4669Sjacobs } 756355b4669Sjacobs break; 757355b4669Sjacobs case '\5': { /* cancel job(s) */ 758*0a44ef6dSjacobs char *user = *args++; 759*0a44ef6dSjacobs char *host = remote_host_name(ifp); 760355b4669Sjacobs int count; 761355b4669Sjacobs 762*0a44ef6dSjacobs if (host != NULL) { 763*0a44ef6dSjacobs char buf[BUFSIZ]; 764*0a44ef6dSjacobs 765*0a44ef6dSjacobs snprintf(buf, sizeof (buf), "%s@%s", user, host); 766*0a44ef6dSjacobs status = papiServiceSetUserName(svc, buf); 767*0a44ef6dSjacobs } else 768*0a44ef6dSjacobs status = papiServiceSetUserName(svc, user); 769*0a44ef6dSjacobs 770355b4669Sjacobs for (count = 0; args[count] != 0; count++); 771355b4669Sjacobs 772355b4669Sjacobs berkeley_cancel_request(svc, ofp, printer, count, args); 773355b4669Sjacobs } 774355b4669Sjacobs break; 775355b4669Sjacobs default: 776355b4669Sjacobs fatal(ofp, "unsupported protocol request (%c), %s", 777355b4669Sjacobs buf[0], &buf[1]); 778355b4669Sjacobs } 779355b4669Sjacobs 780355b4669Sjacobs (void) fflush(ofp); 781355b4669Sjacobs 782355b4669Sjacobs syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s", 783355b4669Sjacobs buf[0], printer, papiStatusString(status)); 784*0a44ef6dSjacobs if (status != PAPI_OK) 785*0a44ef6dSjacobs syslog(LOG_DEBUG, "detail: %s", 786*0a44ef6dSjacobs verbose_papi_message(svc, status)); 787355b4669Sjacobs 788355b4669Sjacobs papiServiceDestroy(svc); 789355b4669Sjacobs 790355b4669Sjacobs return (0); 791355b4669Sjacobs } 792