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 /* 232264Sjacobs * Copyright 2006 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> 34*3125Sjacobs #include <unistd.h> 35*3125Sjacobs #include <fcntl.h> 362264Sjacobs #include <stdarg.h> 372264Sjacobs #include <string.h> 382264Sjacobs #include <errno.h> 392264Sjacobs #include <syslog.h> 402264Sjacobs #include <libintl.h> 41*3125Sjacobs #include <pwd.h> 42*3125Sjacobs #include <grp.h> 43*3125Sjacobs #include <sys/types.h> 44*3125Sjacobs #include <sys/stat.h> 45*3125Sjacobs #include <sys/socket.h> 46*3125Sjacobs #include <netinet/in.h> 47*3125Sjacobs #include <arpa/inet.h> 48*3125Sjacobs #include <netdb.h> 49*3125Sjacobs #include <sys/systeminfo.h> 502264Sjacobs 512264Sjacobs #include <papi.h> 52*3125Sjacobs #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 63*3125Sjacobs static char * 64*3125Sjacobs remote_host_name(FILE *fp) 65*3125Sjacobs { 66*3125Sjacobs struct hostent *hp; 67*3125Sjacobs struct sockaddr_in6 peer; 68*3125Sjacobs socklen_t peer_len = sizeof (peer); 69*3125Sjacobs int fd = fileno(fp); 70*3125Sjacobs int error_num; 71*3125Sjacobs char myname[MAXHOSTNAMELEN], tmp_buf[INET6_ADDRSTRLEN]; 72*3125Sjacobs char *hostname; 73*3125Sjacobs 74*3125Sjacobs /* who is our peer ? */ 75*3125Sjacobs if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) { 76*3125Sjacobs if ((errno != ENOTSOCK) && (errno != EINVAL)) 77*3125Sjacobs return (NULL); 78*3125Sjacobs else 79*3125Sjacobs return (strdup("localhost")); 80*3125Sjacobs } 81*3125Sjacobs 82*3125Sjacobs /* get their name or return a string containing their address */ 83*3125Sjacobs if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr, 84*3125Sjacobs sizeof (struct in6_addr), AF_INET6, 85*3125Sjacobs &error_num)) == NULL) { 86*3125Sjacobs return (strdup(inet_ntop(peer.sin6_family, 87*3125Sjacobs &peer.sin6_addr, tmp_buf, sizeof (tmp_buf)))); 88*3125Sjacobs } 89*3125Sjacobs 90*3125Sjacobs /* is it "localhost" ? */ 91*3125Sjacobs if (strcasecmp(hp->h_name, "localhost") == 0) 92*3125Sjacobs return (strdup("localhost")); 93*3125Sjacobs 94*3125Sjacobs /* duplicate the name because gethostbyXXXX() is not reentrant */ 95*3125Sjacobs hostname = strdup(hp->h_name); 96*3125Sjacobs (void) sysinfo(SI_HOSTNAME, myname, sizeof (myname)); 97*3125Sjacobs 98*3125Sjacobs /* is it from one of my addresses ? */ 99*3125Sjacobs if ((hp = getipnodebyname(myname, AF_INET6, AI_ALL|AI_V4MAPPED, 100*3125Sjacobs &error_num)) != NULL) { 101*3125Sjacobs struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list; 102*3125Sjacobs int i = 0; 103*3125Sjacobs 104*3125Sjacobs while (tmp[i] != NULL) { 105*3125Sjacobs if (memcmp(tmp[i++], &peer.sin6_addr, hp->h_length) 106*3125Sjacobs == 0) { 107*3125Sjacobs free(hostname); 108*3125Sjacobs return (strdup("localhost")); 109*3125Sjacobs } 110*3125Sjacobs } 111*3125Sjacobs } 112*3125Sjacobs 113*3125Sjacobs /* It must be someone else */ 114*3125Sjacobs return (hostname); 115*3125Sjacobs } 116*3125Sjacobs 117*3125Sjacobs 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); 126*3125Sjacobs exit(1); 1272264Sjacobs } 1282264Sjacobs 1292264Sjacobs static void 130*3125Sjacobs cleanup(char ***files, char **cf) 131*3125Sjacobs { 132*3125Sjacobs if (*files != NULL) { 133*3125Sjacobs int i; 134*3125Sjacobs 135*3125Sjacobs for (i = 0; (*files)[i] != NULL; i++) { 136*3125Sjacobs (void) unlink((*files)[i]); 137*3125Sjacobs free((*files)[i]); 138*3125Sjacobs } 139*3125Sjacobs free(*files); 140*3125Sjacobs *files = NULL; 141*3125Sjacobs } 142*3125Sjacobs 143*3125Sjacobs if (*cf != NULL) { 144*3125Sjacobs free(*cf); 145*3125Sjacobs *cf = NULL; 146*3125Sjacobs } 147*3125Sjacobs } 148*3125Sjacobs 149*3125Sjacobs static papi_attribute_t ** 150*3125Sjacobs parse_cf(papi_service_t svc, char *cf, char **files) 1512264Sjacobs { 152*3125Sjacobs papi_attribute_t **list = NULL; 153*3125Sjacobs char previous = NULL, 154*3125Sjacobs *entry, 155*3125Sjacobs *s, 156*3125Sjacobs text[BUFSIZ]; 157*3125Sjacobs int count = 0, 158*3125Sjacobs copies_set = 0, 159*3125Sjacobs copies = 0; 160*3125Sjacobs 161*3125Sjacobs for (entry = strtok(cf, "\n"); entry != NULL; 162*3125Sjacobs entry = strtok(NULL, "\n")) { 163*3125Sjacobs char *format = NULL; 164*3125Sjacobs 165*3125Sjacobs /* count the copies */ 166*3125Sjacobs if ((entry[0] >= 'a') && (entry[0] <= 'z') && 167*3125Sjacobs (copies_set == 0) && (previous == entry[0])) 168*3125Sjacobs copies++; 169*3125Sjacobs else if ((previous >= 'a') && (previous <= 'z')) 170*3125Sjacobs copies_set = 1; 171*3125Sjacobs previous = entry[0]; 1722264Sjacobs 173*3125Sjacobs /* process the control message */ 174*3125Sjacobs switch (entry[0]) { 175*3125Sjacobs /* RFC-1179 options */ 176*3125Sjacobs case 'J': /* RFC-1179 Banner Job Name */ 177*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 178*3125Sjacobs "job-name", ++entry); 179*3125Sjacobs break; 180*3125Sjacobs case 'C': /* RFC-1179 Banner Class Name */ 181*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 182*3125Sjacobs "rfc-1179-class", ++entry); 183*3125Sjacobs break; 184*3125Sjacobs case 'L': /* RFC-1179 Banner toggle */ 185*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 186*3125Sjacobs "job-sheets", "standard"); 187*3125Sjacobs break; 188*3125Sjacobs case 'T': /* RFC-1179 Title (pr) */ 189*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 190*3125Sjacobs "pr-title", ++entry); 191*3125Sjacobs break; 192*3125Sjacobs case 'H': /* RFC-1179 Host */ 193*3125Sjacobs /* 194*3125Sjacobs * use the host as known by us, not by them 195*3125Sjacobs * 196*3125Sjacobs * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 197*3125Sjacobs * "job-originating-host-name", ++entry); 198*3125Sjacobs */ 199*3125Sjacobs break; 200*3125Sjacobs case 'P': /* RFC-1179 User */ 201*3125Sjacobs ++entry; 202*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 203*3125Sjacobs "requesting-user-name", entry); 204*3125Sjacobs papiServiceSetUserName(svc, entry); 205*3125Sjacobs break; 206*3125Sjacobs case 'M': /* RFC-1179 Mail to User */ 207*3125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 208*3125Sjacobs "rfc-1179-mail", 1); 209*3125Sjacobs break; 210*3125Sjacobs case 'W': /* RFC-1179 Width (pr) */ 211*3125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 212*3125Sjacobs "pr-width", atoi(++entry)); 213*3125Sjacobs break; 214*3125Sjacobs case 'I': /* RFC-1179 Indent (pr) */ 215*3125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 216*3125Sjacobs "pr-indent", atoi(++entry)); 217*3125Sjacobs break; 218*3125Sjacobs case 'N': /* RFC-1179 Filename */ 219*3125Sjacobs /* could have HPUX extension embedded */ 220*3125Sjacobs if (entry[1] != ' ') { /* real pathname */ 221*3125Sjacobs #ifdef DEBUG 222*3125Sjacobs papiAttributeListAddString(&list, 223*3125Sjacobs PAPI_ATTR_EXCL, 224*3125Sjacobs "flist", ++entry); 225*3125Sjacobs #endif 226*3125Sjacobs } else if (entry[2] == 'O') /* HPUX lp -o options */ 227*3125Sjacobs papiAttributeListFromString(&list, 228*3125Sjacobs PAPI_ATTR_APPEND, ++entry); 229*3125Sjacobs break; 230*3125Sjacobs case 'U': /* RFC-1179 Unlink */ 231*3125Sjacobs break; /* ignored */ 232*3125Sjacobs case '1': /* RFC-1179 TROFF Font R */ 233*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 234*3125Sjacobs "rfc-1179-font-r", ++entry); 235*3125Sjacobs break; 236*3125Sjacobs case '2': /* RFC-1179 TROFF Font I */ 237*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 238*3125Sjacobs "rfc-1179-font-i", ++entry); 239*3125Sjacobs break; 240*3125Sjacobs case '3': /* RFC-1179 TROFF Font B */ 241*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 242*3125Sjacobs "rfc-1179-font-b", ++entry); 243*3125Sjacobs break; 244*3125Sjacobs case '4': /* RFC-1179 TROFF Font S */ 245*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 246*3125Sjacobs "rfc-1179-font-s", ++entry); 247*3125Sjacobs break; 248*3125Sjacobs case 'f': /* RFC-1179 ASCII file (print) */ 249*3125Sjacobs format = "text/plain"; 250*3125Sjacobs if (is_postscript(files[0]) == 1) 251*3125Sjacobs format = "application/postscript"; 252*3125Sjacobs break; 253*3125Sjacobs case 'l': /* RFC-1179 CATV file (print) */ 254*3125Sjacobs format = "application/octet-stream"; 255*3125Sjacobs if (is_postscript(files[0]) == 1) 256*3125Sjacobs format = "application/postscript"; 257*3125Sjacobs break; 258*3125Sjacobs case 'o': /* RFC-1179 Postscript file (print) */ 259*3125Sjacobs format = "application/postscript"; 260*3125Sjacobs break; 261*3125Sjacobs case 'p': /* RFC-1179 PR file (print) */ 262*3125Sjacobs format = "application/x-pr"; 263*3125Sjacobs papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 264*3125Sjacobs "pr-filter", 1); 265*3125Sjacobs break; 266*3125Sjacobs case 't': /* RFC-1179 TROFF file (print) */ 267*3125Sjacobs format = "application/x-troff"; 268*3125Sjacobs break; 269*3125Sjacobs case 'n': /* RFC-1179 DITROFF file (print) */ 270*3125Sjacobs format = "application/x-ditroff"; 271*3125Sjacobs break; 272*3125Sjacobs case 'd': /* RFC-1179 DVI file (print) */ 273*3125Sjacobs format = "application/x-dvi"; 274*3125Sjacobs break; 275*3125Sjacobs case 'g': /* RFC-1179 GRAPH file (print) */ 276*3125Sjacobs format = "application/x-plot"; 277*3125Sjacobs break; 278*3125Sjacobs case 'c': /* RFC-1179 CIF file (print) */ 279*3125Sjacobs format = "application/x-cif"; 280*3125Sjacobs break; 281*3125Sjacobs case 'v': /* RFC-1179 RASTER file (print) */ 282*3125Sjacobs format = "application/x-raster"; 283*3125Sjacobs break; 284*3125Sjacobs case 'r': /* RFC-1179 FORTRAN file (print) */ 285*3125Sjacobs format = "application/x-fortran"; 286*3125Sjacobs break; 287*3125Sjacobs /* Sun Solaris Extensions */ 288*3125Sjacobs case 'O': 289*3125Sjacobs ++entry; 290*3125Sjacobs do { 291*3125Sjacobs if (*entry != '"') 292*3125Sjacobs text[count++] = *entry; 293*3125Sjacobs } while (*entry++); 294*3125Sjacobs papiAttributeListFromString(&list, PAPI_ATTR_APPEND, 295*3125Sjacobs text); 296*3125Sjacobs break; 297*3125Sjacobs case '5': 298*3125Sjacobs ++entry; 299*3125Sjacobs switch (entry[0]) { 300*3125Sjacobs case 'f': /* Solaris form */ 301*3125Sjacobs papiAttributeListAddString(&list, 302*3125Sjacobs PAPI_ATTR_EXCL, 303*3125Sjacobs "form", ++entry); 304*3125Sjacobs break; 305*3125Sjacobs case 'H': /* Solaris handling */ 306*3125Sjacobs ++entry; 307*3125Sjacobs if (strcasecmp(entry, "hold") == 0) 308*3125Sjacobs papiAttributeListAddString(&list, 309*3125Sjacobs PAPI_ATTR_EXCL, 310*3125Sjacobs "job-hold-until", "indefinite"); 311*3125Sjacobs else if (strcasecmp(entry, "release") == 0) 312*3125Sjacobs papiAttributeListAddString(&list, 313*3125Sjacobs PAPI_ATTR_EXCL, 314*3125Sjacobs "job-hold-until", "no-hold"); 315*3125Sjacobs else if (strcasecmp(entry, "immediate") == 0) 316*3125Sjacobs papiAttributeListAddInteger(&list, 317*3125Sjacobs PAPI_ATTR_EXCL, 318*3125Sjacobs "job-priority", 100); 319*3125Sjacobs else 320*3125Sjacobs papiAttributeListAddString(&list, 321*3125Sjacobs PAPI_ATTR_EXCL, 322*3125Sjacobs "job-hold-until", entry); 323*3125Sjacobs break; 324*3125Sjacobs case 'p': /* Solaris notification */ 325*3125Sjacobs papiAttributeListAddBoolean(&list, 326*3125Sjacobs PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 327*3125Sjacobs break; 328*3125Sjacobs case 'P': /* Solaris page list */ 329*3125Sjacobs papiAttributeListAddString(&list, 330*3125Sjacobs PAPI_ATTR_EXCL, 331*3125Sjacobs "page-ranges", ++entry); 332*3125Sjacobs break; 333*3125Sjacobs case 'q': { /* Solaris priority */ 334*3125Sjacobs int i = atoi(optarg); 335*3125Sjacobs 336*3125Sjacobs i = 99 * (39 - i) / 39 + 1; 337*3125Sjacobs if ((i < 1) || (i > 100)) 338*3125Sjacobs i = 50; 339*3125Sjacobs papiAttributeListAddInteger(&list, 340*3125Sjacobs PAPI_ATTR_EXCL, "priority", i); 341*3125Sjacobs } 342*3125Sjacobs break; 343*3125Sjacobs case 'S': /* Solaris character set */ 344*3125Sjacobs papiAttributeListAddString(&list, 345*3125Sjacobs PAPI_ATTR_EXCL, "lp-charset", 346*3125Sjacobs ++entry); 347*3125Sjacobs break; 348*3125Sjacobs case 'T': /* Solaris type */ 349*3125Sjacobs format = lp_type_to_mime_type(++entry); 350*3125Sjacobs break; 351*3125Sjacobs case 'y': /* Solaris mode */ 352*3125Sjacobs papiAttributeListAddString(&list, 353*3125Sjacobs PAPI_ATTR_APPEND, "lp-modes", ++entry); 354*3125Sjacobs break; 355*3125Sjacobs default: 356*3125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 357*3125Sjacobs "Warning: cf message (%s) ignored", 358*3125Sjacobs entry); 359*3125Sjacobs break; 360*3125Sjacobs } 361*3125Sjacobs break; 362*3125Sjacobs /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 363*3125Sjacobs 364*3125Sjacobs default: 365*3125Sjacobs syslog(LOG_INFO|LOG_DEBUG, 366*3125Sjacobs "Warning: cf message (%s) ignored", entry); 367*3125Sjacobs break; 368*3125Sjacobs } 369*3125Sjacobs 370*3125Sjacobs if (format != NULL) 371*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 372*3125Sjacobs "document-format", format); 373*3125Sjacobs } 374*3125Sjacobs 375*3125Sjacobs papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 376*3125Sjacobs "copies", ++copies); 377*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 378*3125Sjacobs "job-sheets", "none"); 379*3125Sjacobs 380*3125Sjacobs return (list); 381*3125Sjacobs } 382*3125Sjacobs 383*3125Sjacobs static papi_status_t 384*3125Sjacobs submit_job(papi_service_t svc, FILE *ifp, char *printer, char *cf, char **files) 385*3125Sjacobs { 386*3125Sjacobs papi_attribute_t **list = NULL; 387*3125Sjacobs papi_status_t status; 388*3125Sjacobs papi_job_t job = NULL; 389*3125Sjacobs char *format = ""; 390*3125Sjacobs 391*3125Sjacobs if ((list = parse_cf(svc, cf, files)) != NULL) { 392*3125Sjacobs /* use the host as known by us, not by them */ 393*3125Sjacobs char *host = remote_host_name(ifp); 394*3125Sjacobs 395*3125Sjacobs if (host != NULL) { 396*3125Sjacobs papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 397*3125Sjacobs "job-originating-host-name", host); 398*3125Sjacobs free(host); 399*3125Sjacobs } 400*3125Sjacobs } 401*3125Sjacobs 402*3125Sjacobs status = papiJobSubmit(svc, printer, list, NULL, files, &job); 403*3125Sjacobs syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 404*3125Sjacobs if (status != PAPI_OK) { 405*3125Sjacobs char *tmp = papiServiceGetStatusMessage(svc); 406*3125Sjacobs 407*3125Sjacobs syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 408*3125Sjacobs } 409*3125Sjacobs papiJobFree(job); 410*3125Sjacobs 411*3125Sjacobs return (status); 412*3125Sjacobs } 413*3125Sjacobs 414*3125Sjacobs static char * 415*3125Sjacobs receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 416*3125Sjacobs { 417*3125Sjacobs char *ptr, *cf_data; 418*3125Sjacobs 419*3125Sjacobs if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 420*3125Sjacobs NACK(ofp); 421*3125Sjacobs return (NULL); 422*3125Sjacobs } else 423*3125Sjacobs ACK(ofp); 424*3125Sjacobs 425*3125Sjacobs while (size > 0) { 426*3125Sjacobs int rc; 427*3125Sjacobs 428*3125Sjacobs if (((rc = fread(ptr, 1, size, ifp)) == 0) && 429*3125Sjacobs (feof(ifp) != 0)) { 430*3125Sjacobs free(cf_data); 431*3125Sjacobs return (NULL); 432*3125Sjacobs } else { 433*3125Sjacobs ptr += rc; 434*3125Sjacobs size -= rc; 435*3125Sjacobs } 436*3125Sjacobs } 437*3125Sjacobs syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 438*3125Sjacobs 439*3125Sjacobs if (fgetc(ifp) != 0) { 440*3125Sjacobs free(cf_data); 441*3125Sjacobs return (NULL); 442*3125Sjacobs } 4432264Sjacobs ACK(ofp); 4442264Sjacobs 445*3125Sjacobs return (cf_data); 446*3125Sjacobs } 447*3125Sjacobs 448*3125Sjacobs static char * 449*3125Sjacobs receive_data_file(FILE *ifp, FILE *ofp, int size) 450*3125Sjacobs { 451*3125Sjacobs char file[] = "lpdXXXXXX"; 452*3125Sjacobs char buf[BUFSIZ]; 453*3125Sjacobs int fd; 454*3125Sjacobs 455*3125Sjacobs if ((fd = mkstemp(file)) < 0) { 456*3125Sjacobs NACK(ofp); 457*3125Sjacobs return (NULL); 458*3125Sjacobs } else 459*3125Sjacobs ACK(ofp); 460*3125Sjacobs 461*3125Sjacobs while (size > 0) { 462*3125Sjacobs int rc = ((size > BUFSIZ) ? BUFSIZ : size); 463*3125Sjacobs 464*3125Sjacobs if (((rc = fread(buf, 1, rc, ifp)) == 0) && 465*3125Sjacobs (feof(ifp) != 0)) { 466*3125Sjacobs close(fd); 467*3125Sjacobs unlink(file); 468*3125Sjacobs return (NULL); 469*3125Sjacobs } else { 470*3125Sjacobs char *ptr = buf; 471*3125Sjacobs 472*3125Sjacobs while (rc > 0) { 473*3125Sjacobs int wrc = write(fd, ptr, rc); 474*3125Sjacobs 475*3125Sjacobs if (wrc < 0) { 476*3125Sjacobs close(fd); 477*3125Sjacobs unlink(file); 478*3125Sjacobs return(NULL); 479*3125Sjacobs } 480*3125Sjacobs 481*3125Sjacobs ptr += wrc; 482*3125Sjacobs size -= wrc; 483*3125Sjacobs rc -= wrc; 484*3125Sjacobs } 485*3125Sjacobs } 486*3125Sjacobs } 487*3125Sjacobs close(fd); 488*3125Sjacobs if (fgetc(ifp) != 0) { 489*3125Sjacobs unlink(file); 490*3125Sjacobs return (NULL); 491*3125Sjacobs } 492*3125Sjacobs ACK(ofp); 493*3125Sjacobs 494*3125Sjacobs return (strdup(file)); 495*3125Sjacobs } 496*3125Sjacobs 497*3125Sjacobs static papi_status_t 498*3125Sjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 499*3125Sjacobs { 500*3125Sjacobs papi_status_t status = PAPI_OK; 501*3125Sjacobs char *file, **files = NULL; /* the job data files */ 502*3125Sjacobs char *cf = NULL; 503*3125Sjacobs char buf[BUFSIZ]; 504*3125Sjacobs 505*3125Sjacobs while (fgets(buf, sizeof (buf), ifp) != NULL) { 506*3125Sjacobs int size; 507*3125Sjacobs 508*3125Sjacobs syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 509*3125Sjacobs #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 510*3125Sjacobs if ((buf[0] > '0') && (buf[0] < '4')) 511*3125Sjacobs buf[0] -= '0'; 512*3125Sjacobs #endif 513*3125Sjacobs switch (buf[0]) { 5142264Sjacobs case 0x01: /* Abort */ 515*3125Sjacobs cleanup(&files, &cf); 5162264Sjacobs break; 517*3125Sjacobs case 0x02: { /* Receive control file */ 518*3125Sjacobs cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1])); 519*3125Sjacobs if (cf == NULL) { 520*3125Sjacobs cleanup(&files, &cf); 521*3125Sjacobs return (PAPI_BAD_REQUEST); 522*3125Sjacobs } else if (files != NULL) { 523*3125Sjacobs status = submit_job(svc, ifp, printer, cf, 524*3125Sjacobs files); 525*3125Sjacobs cleanup(&files, &cf); 526*3125Sjacobs } 527*3125Sjacobs } 5282264Sjacobs break; 5292264Sjacobs case 0x03: { /* Receive data file */ 530*3125Sjacobs file = receive_data_file(ifp, ofp, atoi(&buf[1])); 531*3125Sjacobs if (file == NULL) { 532*3125Sjacobs cleanup(&files, &cf); 533*3125Sjacobs return (PAPI_TEMPORARY_ERROR); 534*3125Sjacobs } 535*3125Sjacobs list_append(&files, file); 5362264Sjacobs } 5372264Sjacobs break; 5382264Sjacobs default: 539*3125Sjacobs cleanup(&files, &cf); 5402264Sjacobs fatal(ofp, "protocol screwup"); 5412264Sjacobs break; 5422264Sjacobs } 5432264Sjacobs } 5442264Sjacobs 545*3125Sjacobs if ((cf != NULL) && (files != NULL)) 546*3125Sjacobs status = submit_job(svc, ifp, printer, cf, files); 547*3125Sjacobs 548*3125Sjacobs cleanup(&files, &cf); 549*3125Sjacobs 550*3125Sjacobs return (status); 5512264Sjacobs } 5522264Sjacobs 553*3125Sjacobs 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; 559*3125Sjacobs 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, 567*3125Sjacobs "printer-is-accepting-jobs", &accepting); 5682264Sjacobs 569*3125Sjacobs if (accepting == PAPI_TRUE) { 570*3125Sjacobs ACK(ofp); 571*3125Sjacobs status = berkeley_receive_files(svc, ifp, ofp, printer); 572*3125Sjacobs } else 5732264Sjacobs NACK(ofp); 5742264Sjacobs 5752264Sjacobs papiPrinterFree(p); 5762264Sjacobs } else 5772264Sjacobs NACK(ofp); 578*3125Sjacobs 579*3125Sjacobs return (status); 5802264Sjacobs } 5812264Sjacobs 582*3125Sjacobs static int 583*3125Sjacobs cyclical_service_check(char *svc_name) 584*3125Sjacobs { 585*3125Sjacobs papi_attribute_t **list; 586*3125Sjacobs char buf[BUFSIZ]; 587*3125Sjacobs uri_t *uri = NULL; 588*3125Sjacobs char *s = NULL; 589*3125Sjacobs 590*3125Sjacobs /* was there a printer? */ 591*3125Sjacobs if (svc_name == NULL) 592*3125Sjacobs return (0); 593*3125Sjacobs 594*3125Sjacobs if ((list = getprinterbyname(svc_name, NULL)) == NULL) 595*3125Sjacobs return (0); /* if it doesnt' resolve, we will fail later */ 596*3125Sjacobs 597*3125Sjacobs papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 598*3125Sjacobs if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 599*3125Sjacobs return (0); /* they don't match */ 600*3125Sjacobs 601*3125Sjacobs /* is it in uri form? */ 602*3125Sjacobs if (uri_from_string(s, &uri) < 0) 603*3125Sjacobs return (0); 604*3125Sjacobs 605*3125Sjacobs if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 606*3125Sjacobs uri_free(uri); 607*3125Sjacobs return (0); 608*3125Sjacobs } 609*3125Sjacobs 610*3125Sjacobs /* is it in lpd form? */ 611*3125Sjacobs if (strcasecmp(uri->scheme, "lpd") != 0) { 612*3125Sjacobs uri_free(uri); 613*3125Sjacobs return (0); 614*3125Sjacobs } 615*3125Sjacobs 616*3125Sjacobs /* is it the local host? */ 617*3125Sjacobs sysinfo(SI_HOSTNAME, buf, sizeof (buf)); 618*3125Sjacobs if ((strcasecmp(uri->host, "localhost") != 0) && 619*3125Sjacobs (strcasecmp(uri->host, buf) != 0)) { 620*3125Sjacobs uri_free(uri); 621*3125Sjacobs return (0); 622*3125Sjacobs } 623*3125Sjacobs 624*3125Sjacobs uri_free(uri); 625*3125Sjacobs return (1); 626*3125Sjacobs } 627*3125Sjacobs 628*3125Sjacobs 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, 645*3125Sjacobs *printer, 646*3125Sjacobs *run_dir = "/var/run/in.lpd", 647*3125Sjacobs *run_user = NULL; 648*3125Sjacobs struct passwd *pw = NULL; 6492264Sjacobs 650*3125Sjacobs (void) chdir("/tmp"); /* run in /tmp by default */ 6512264Sjacobs openlog("bsd-gw", LOG_PID, LOG_LPR); 6522264Sjacobs 653*3125Sjacobs while ((c = getopt(ac, av, "Ed:u:")) != EOF) 6542264Sjacobs switch (c) { 6552264Sjacobs case 'E': 6562264Sjacobs encryption = PAPI_ENCRYPT_ALWAYS; 6572264Sjacobs break; 658*3125Sjacobs case 'd': /* run where they tell you */ 659*3125Sjacobs run_dir = optarg; 660*3125Sjacobs break; 661*3125Sjacobs case 'u': /* run as */ 662*3125Sjacobs run_user = optarg; 663*3125Sjacobs break; 6642264Sjacobs default: 6652264Sjacobs ; 6662264Sjacobs } 6672264Sjacobs 668*3125Sjacobs if (run_user != NULL) /* get the requested user info */ 669*3125Sjacobs pw = getpwnam(run_user); 670*3125Sjacobs 671*3125Sjacobs if (run_dir != NULL) { /* setup the run_dir */ 672*3125Sjacobs (void) mkdir(run_dir, 0700); 673*3125Sjacobs if (pw != NULL) 674*3125Sjacobs (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 675*3125Sjacobs } 676*3125Sjacobs 677*3125Sjacobs if (pw != NULL) { /* run as the requested user */ 678*3125Sjacobs syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 679*3125Sjacobs pw->pw_name, pw->pw_uid, pw->pw_gid); 680*3125Sjacobs initgroups(pw->pw_name, pw->pw_gid); 681*3125Sjacobs setgid(pw->pw_gid); 682*3125Sjacobs setuid(pw->pw_uid); 683*3125Sjacobs } 684*3125Sjacobs 685*3125Sjacobs if (run_dir != NULL) /* move to the run_dir */ 686*3125Sjacobs if (chdir(run_dir) < 0) { 687*3125Sjacobs syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 688*3125Sjacobs exit(1); 689*3125Sjacobs } 690*3125Sjacobs 691*3125Sjacobs syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 692*3125Sjacobs 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 700*3125Sjacobs syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 701*3125Sjacobs 702*3125Sjacobs #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 703*3125Sjacobs if ((buf[0] > '0') && (buf[0] < '6')) 704*3125Sjacobs buf[0] -= '0'; 705*3125Sjacobs #endif 706*3125Sjacobs 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 721*3125Sjacobs if (cyclical_service_check(printer) != 0) { 722*3125Sjacobs fatal(ofp, "%s is cyclical\n", printer); 723*3125Sjacobs exit(1); 724*3125Sjacobs } 725*3125Sjacobs 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 734*3125Sjacobs /* 735*3125Sjacobs * Trusted Solaris can't be trusting of intermediaries. Pass 736*3125Sjacobs * the socket connection to the print service to retrieve the 737*3125Sjacobs * sensativity label off of a multi-level port. 738*3125Sjacobs */ 739*3125Sjacobs (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) */ 746*3125Sjacobs 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) */ 758*3125Sjacobs char *user = *args++; 759*3125Sjacobs char *host = remote_host_name(ifp); 7602264Sjacobs int count; 7612264Sjacobs 762*3125Sjacobs if (host != NULL) { 763*3125Sjacobs char buf[BUFSIZ]; 764*3125Sjacobs 765*3125Sjacobs snprintf(buf, sizeof (buf), "%s@%s", user, host); 766*3125Sjacobs status = papiServiceSetUserName(svc, buf); 767*3125Sjacobs } else 768*3125Sjacobs status = papiServiceSetUserName(svc, user); 769*3125Sjacobs 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)); 784*3125Sjacobs if (status != PAPI_OK) 785*3125Sjacobs syslog(LOG_DEBUG, "detail: %s", 786*3125Sjacobs verbose_papi_message(svc, status)); 7872264Sjacobs 7882264Sjacobs papiServiceDestroy(svc); 7892264Sjacobs 7902264Sjacobs return (0); 7912264Sjacobs } 792